// bdlde_utf8util.t.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdlde_utf8util.h>

#include <bdlb_random.h>
#include <bdlsb_fixedmeminstreambuf.h>

#include <bslim_testutil.h>

#include <bsls_asserttest.h>
#include <bsls_log.h>
#include <bsls_review.h>
#include <bsls_types.h>

#include <bsl_algorithm.h>
#include <bsl_climits.h>
#include <bsl_cstdlib.h>
#include <bsl_cstring.h>
#include <bsl_iostream.h>
#include <bsl_limits.h>
#include <bsl_sstream.h>
#include <bsl_string.h>
#include <bsl_vector.h>

using namespace BloombergLP;
using bsl::cout;
using bsl::cerr;
using bsl::endl;
using bsl::flush;
using bsl::size_t;

// Suppress some bde_verify warnings for this test driver.
// BDE_VERIFY pragma: -IND01
// BDE_VERIFY pragma: -IND04
// BDE_VERIFY pragma: -SP01
// BDE_VERIFY pragma: -SP03
// BDE_VERIFY pragma: -TP21

//=============================================================================
//                             TEST PLAN
//
//: o Test case 1 is the BREATHING TEST.
//:
//: o Test case 2 tests the validity checking routines on valid UTF-8
//:   sequences.
//:
//: o Test case 3 tests the behavior of byte-order marks.
//:
//: o Test case 4 tests the behavior of surrogates.
//:
//: o Test case 5 tests that the "raw" functions that count code points count
//:   correctly on valid strings.
//:
//: o Test case 6 runs a table-driven test on valid and invalid UTF-8 strings
//:   and observes that the various overloads of 'isValid' and
//:   'numCodePointsIfValid' all detect the invalid sequences.
//:
//: o Test case 7 tests the 'advance' functions on one very long string of
//:   valid UTF-8 of real, human-generated prose in Chinese, Hindi, French, and
//:   Greek and code points of all sizes (but no embedded '\0's).
//:
//: o Test case 8 tests the various functions, including, for the first time,
//:   'readIfValid', on valid randomly-generated UTF-8 sequences.
//:
//: o Test case 9 is the "broken glass" test -- testing strings that contain a
//:   mix of valid and invalid UTF-8, using a mix of table data and
//:   randomly-generated data.
//:
//: o Test case 10 tests 'numBytesRaw'.
//:
//: o Test case 11 is a table-driven test to test 'numBytesInCodePoint'.
//:
//: o Test case 12 tests 'appendUtf8CodePoint' on valid Unicode characters.
//:
//: o Test case 13 is a table-driven test of the 'toAscii' class method.
//:
//: o Test case 14 is negative testing.
//:
//: o Test cases 15, 16, and 17 are USAGE EXAMPLES.
//
//-----------------------------------------------------------------------------
// To fit functions on one line, 'typedef const char cchar'.
//
// CLASS METHODS
// [ 4] IntPtr advanceIfValid(int *, const char **, const char *, int);
// [ 4] IntPtr advanceIfValid(int*,const char**,const char *,int,int);
// [ 7] IntPtr advanceIfValid(int *, const char **, const char *, int);
// [ 7] IntPtr advanceIfValid(int*,const char**,const char *,int,int);
// [ 8] IntPtr advanceIfValid(int *, const char **, const char *, int);
// [ 8] IntPtr advanceIfValid(int *, const char **, const char *,int,int);
// [ 9] IntPtr advanceIfValid(int *, cchar **,  cchar *, IntPtr);
// [ 9] IntPtr advanceIfValid(int *, cchar **, cchar *, size_t, IntPtr);
// [ 7] IntPtr advanceRaw(const char **, const char *, int);
// [ 7] IntPtr advanceRaw(const char **, const char *, int, int);
// [ 8] IntPtr advanceRaw(const char **, const char *, int);
// [ 8] IntPtr advanceRaw(const char **, const char *, int, int);
// [12] int appendUtf8CodePoint(bsl::string *, unsigned int);
// [12] int appendUtf8Character(bsl::string *, unsigned int);
// [11] int numBytesInCodePoint(const char *);
// [11] int getByteSize(const char *);
// [ 3] bool isValid(const char *s);
// [ 9] bool isValid(cchar *);
// [ 3] bool isValid(const char *s, int len);
// [ 9] bool isValid(cchar *, size_t);
// [ 3] bool isValid(const char **err, const char *s);
// [ 9] bool isValid(cchar **, cchar *);
// [ 3] bool isValid(const char **err, const char *s, int len);
// [ 9] bool isValid(cchar **, cchar *, size_t);
// [ 4] bool isValid(const char *s);
// [ 4] bool isValid(const char *s, int len);
// [ 4] bool isValid(const char **err, const char *s);
// [ 4] bool isValid(const char **err, const char *s, int len);
// [ 6] bool isValid(const char *s);
// [ 6] bool isValid(const char *s, int len);
// [ 6] bool isValid(const char **err, const char *s);
// [ 6] bool isValid(const char **err, const char *s, int len);
// [ 8] bool isValid(const char *);
// [ 8] bool isValid(const char *, int);
// [ 8] bool isValid(const char **, const char *);
// [ 8] bool isValid(const char **, const char *, int);
// [10] IntPtr numBytesRaw(const bslstl::StringRef&, IntPtr);
// [10] IntPtr numBytesIfValid(const bslstl::StringRef&, IntPtr);
// [ 5] IntPtr numCharacters(const char *s);
// [ 5] IntPtr numCharacters(const char *s, int len);
// [ 6] IntPtr numCharactersIfValid(**err, const char *s);
// [ 6] IntPtr numCharactersIfValid(**err, const char *s, int len);
// [ 5] IntPtr numCharactersRaw(const char *s, int len);
// [ 5] IntPtr numCharactersRaw(const char *s);
// [ 4] IntPtr numCodePointsIfValid(**err, const char *s);
// [ 9] IntPtr numCodePointsIfValid(cchar **, cchar *);
// [ 4] IntPtr numCodePointsIfValid(**err, const char *s, int len);
// [ 9] IntPtr numCodePointsIfValid(cchar **, const char *, int);
// [ 9] IntPtr numCodePointsIfValid(cchar **, cchar *, IntPtr);
// [ 6] IntPtr numCodePointsIfValid(**err, const char *s);
// [ 8] IntPtr numCodePointsIfValid(const char **, const char *);
// [ 6] IntPtr numCodePointsIfValid(**err, const char *s, int len);
// [ 8] IntPtr numCodePointsIfValid(const char **, const char *, int);
// [ 5] IntPtr numCodePointsRaw(const char *s);
// [ 5] IntPtr numCodePointsRaw(const char *s, int len);
// [ 8] size_t readIfValid(int *, char *, size_t, streambuf *);
// [ 9] IntPtr readIfValid(int *, cchar *, size_t, streambuf *);
// [13] const char *toAscii(IntPtr);
//-----------------------------------------------------------------------------
// [ 1] BREATHING TEST
// [ 2] TABLE-DRIVEN ENCODING / DECODING / VALIDATION TEST
// [14] NEGATIVE TESTING
// [15] USAGE EXAMPLE 1
// [16] USAGE EXAMPLE 2
// [17] USAGE EXAMPLE 3
// [-1] random number generator
// [-2] 'utf8Encode', 'decode'

// ============================================================================
//                     STANDARD BDE ASSERT TEST FUNCTION
// ----------------------------------------------------------------------------

namespace {

int testStatus = 0;

void aSsErT(bool condition, const char *message, int line)
{
    if (condition) {
        cout << "Error " __FILE__ "(" << line << "): " << message
             << "    (failed)" << endl;

        if (0 <= testStatus && testStatus <= 100) {
            ++testStatus;
        }
    }
}

}  // close unnamed namespace

// ============================================================================
//               STANDARD BDE TEST DRIVER MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------

#define ASSERT       BSLIM_TESTUTIL_ASSERT
#define ASSERTV      BSLIM_TESTUTIL_ASSERTV

#define LOOP_ASSERT  BSLIM_TESTUTIL_LOOP_ASSERT
#define LOOP0_ASSERT BSLIM_TESTUTIL_LOOP0_ASSERT
#define LOOP1_ASSERT BSLIM_TESTUTIL_LOOP1_ASSERT
#define LOOP2_ASSERT BSLIM_TESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLIM_TESTUTIL_LOOP3_ASSERT
#define LOOP4_ASSERT BSLIM_TESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLIM_TESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLIM_TESTUTIL_LOOP6_ASSERT

#define Q            BSLIM_TESTUTIL_Q   // Quote identifier literally.
#define P            BSLIM_TESTUTIL_P   // Print identifier and value.
#define P_           BSLIM_TESTUTIL_P_  // P(X) without '\n'.
#define T_           BSLIM_TESTUTIL_T_  // Print a tab (w/o newline).
#define L_           BSLIM_TESTUTIL_L_  // current Line number

// ============================================================================
//                  NEGATIVE-TEST MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------

#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)
#define ASSERT_PASS(EXPR)      BSLS_ASSERTTEST_ASSERT_PASS(EXPR)
#define ASSERT_FAIL(EXPR)      BSLS_ASSERTTEST_ASSERT_FAIL(EXPR)
#define ASSERT_OPT_PASS(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR)
#define ASSERT_OPT_FAIL(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR)

// ============================================================================
//         GLOBAL TYPEDEFS, CONSTANTS, ROUTINES & MACROS FOR TESTING
// ----------------------------------------------------------------------------

typedef bdlde::Utf8Util     Obj;
typedef bsls::Types::IntPtr IntPtr;

static int verbose;
static int veryVerbose;
static int veryVeryVerbose;
static int veryVeryVeryVerbose;

static unsigned char utf8MultiLang[] = {
    239,  187, 191,  'C', 'h', 'i',  'n',  'e', 's', 'e', ':',  13,  10,  13,
    10,   228, 184,  173, 229, 141,  142,  228, 186, 186, 230,  176, 145, 229,
    133,  177, 229,  146, 140, 229,  155,  189, 239, 188, 140,  233, 128, 154,
    231,  167, 176,  228, 184, 173,  229,  155, 189, '[', 230,  179, 168, ' ',
    '3',  ']', 239,  188, 140, 230,  152,  175, 228, 189, 141,  230, 150, 188,
    228,  186, 154,  230, 180, 178,  230,  157, 177, 233, 131,  168, 227, 128,
    129,  229, 164,  170, 229, 185,  179,  230, 180, 139, 232,  165, 191, 229,
    178,  184, 231,  154, 132, 228,  184,  128, 228, 184, 170,  231, 164, 190,
    228,  188, 154,  228, 184, 187,  228,  185, 137, 229, 155,  189, 229, 174,
    182,  227, 128,  130, 233, 166,  150,  233, 131, 189, 231,  130, 186, 229,
    140,  151, 228,  186, 172, 227,  128,  130, 229, 133, 182,  233, 153, 134,
    229,  156, 176,  231, 150, 134,  229,  159, 159, 232, 136,  135, 229, 145,
    168,  233, 130,  138, '1', '4',  229,  128, 139, 229, 156,  139, 229, 174,
    182,  230, 142,  165, 229, 163,  164,  239, 188, 140, 233,  153, 134, 229,
    156,  176, 229,  143, 138, 230,  185,  150, 230, 179, 138,  231, 154, 132,
    230,  128, 187,  233, 157, 162,  231,  169, 141, 231, 186,  166, '9', '6',
    '0',  232, 144,  172, 229, 185,  179,  230, 150, 185, 229,  133, 172, 233,
    135,  140, '[',  '1', '1', ']',  '[',  '1', '2', ']', '[',  '1', '3', ']',
    239,  188, 140,  230, 152, 175,  229,  133, 168, 228, 184,  150, 231, 149,
    140,  233, 153,  134, 229, 156,  176,  233, 157, 162, 231,  167, 175, 231,
    172,  172, 228,  186, 140, 229,  164,  167, 231, 154, 132,  229, 155, 189,
    229,  174, 182,  239, 188, 140,  230,  128, 187, 233, 157,  162, 231, 167,
    175,  231, 172,  172, 228, 184,  137,  230, 136, 150, 231,  172, 172, 229,
    155,  155, 229,  164, 167, 231,  154,  132, 229, 155, 189,  229, 174, 182,
    227,  128, 130,  229, 133, 182,  228,  186, 186, 229, 143,  163, 232, 182,
    133,  233, 129,  142, '1', '3',  229,  132, 132, 239, 188,  140, 231, 180,
    132,  228, 189,  148, 229, 133,  168,  231, 144, 131, 228,  186, 186, 229,
    143,  163, 231,  154, 132, 228,  186,  148, 229, 136, 134,  228, 185, 139,
    228,  184, 128,  239, 188, 140,  230,  152, 175, 228, 184,  150, 231, 149,
    140,  228, 184,  138, 228, 186,  186,  229, 143, 163, 230,  156, 128, 229,
    164,  154, 231,  154, 132, 229,  156,  139, 229, 174, 182,  227, 128, 130,
    13,   10,  13,   10,  228, 189,  156,  231, 130, 186, 231,  164, 190, 228,
    188,  154, 228,  184, 187, 228,  185,  137, 229, 155, 189,  229, 174, 182,
    239,  188, 140,  228, 184, 173,  232,  143, 175, 228, 186,  186, 230, 176,
    145,  229, 133,  177, 229, 146,  140,  229, 156, 139, 228,  187, 165, 233,
    169,  172, 229,  133, 139, 230,  128,  157, 229, 136, 151,  229, 174, 129,
    228,  184, 187,  228, 185, 137,  231,  130, 186, 230, 132,  143, 232, 173,
    152,  229, 189,  162, 230, 133,  139,  239, 188, 140, 228,  190, 157, 228,
    184,  173, 229,  156, 139, 231,  137,  185, 232, 137, 178,  231, 164, 190,
    230,  156, 131,  228, 184, 187,  231,  190, 169, 231, 144,  134, 232, 174,
    186,  230, 140,  135, 229, 176,  142,  230, 148, 191, 228,  186, 139, 239,
    188,  140, 229,  185, 182, 231,  148,  177, 230, 134, 178,  230, 179, 149,
    230,  137, 128,  232, 179, 166,  228,  186, 136, 228, 184,  173, 229, 155,
    189,  229, 133,  177, 228, 186,  167,  229, 133, 154, 229,  159, 183, 230,
    148,  191, 239,  188, 140, 229,  174,  158, 232, 161, 140,  228, 184, 173,
    229,  155, 189,  229, 133, 177,  228,  186, 167, 229, 133,  154, 233, 162,
    134,  229, 175,  188, 231, 154,  132,  229, 164, 154, 229,  133, 154, 229,
    144,  136, 228,  189, 156, 229,  146,  140, 230, 148, 191,  230, 178, 187,
    229,  141, 143,  229, 149, 134,  229,  136, 182, 229, 186,  166, '[', '1',
    '4',  ']', 227,  128, 130, '1',  '9',  '4', '9', 229, 185,  180, '1', '0',
    230,  156, 136,  '1', 230, 151,  165,  231, 154, 132, 229,  188, 128, 229,
    155,  189, 229,  164, 167, 229,  133,  184, 228, 184, 173,  239, 188, 140,
    228,  184, 173,  229, 141, 142,  228,  186, 186, 230, 176,  145, 229, 133,
    177,  229, 146,  140, 229, 155,  189,  228, 184, 173, 229,  164, 174, 228,
    186,  186, 230,  176, 145, 230,  148,  191, 229, 186, 156,  230, 173, 163,
    229,  188, 143,  229, 174, 163,  229,  145, 138, 230, 136,  144, 231, 171,
    139,  '[', 230,  179, 168, ' ',  '4',  ']', 227, 128, 130,  229, 133, 168,
    229,  156, 139,  229, 138, 131,  229,  136, 134, 231, 130,  186, '2', '3',
    229,  128, 139,  231, 156, 129,  239,  188, 136, 229, 133,  182, 228, 184,
    173,  229, 185,  182, 230, 178,  161,  230, 156, 137, 229,  175, 185, 229,
    143,  176, 230,  185, 190, 231,  156,  129, 229, 133, 168,  233, 131, 168,
    228,  184, 142,  231, 166, 143,  229,  187, 186, 231, 156,  129, 227, 128,
    129,  230, 181,  183, 229, 141,  151,  231, 156, 129, 233,  131, 168, 229,
    136,  134, 229,  156, 176, 229,  140,  186, 229, 174, 158,  233, 153, 133,
    231,  174, 161,  232, 190, 150,  239,  188, 137, 227, 128,  129, '5', 229,
    128,  139, 232,  135, 170, 230,  178,  187, 229, 141, 128,  227, 128, 129,
    '4',  229, 128,  139, 231, 155,  180,  232, 190, 150, 229,  184, 130, 229,
    146,  140, '2',  229, 128, 139,  231,  137, 185, 229, 136,  165, 232, 161,
    140,  230, 148,  191, 229, 140,  186,  239, 188, 136, 229,  141, 179, 233,
    166,  153, 230,  184, 175, 232,  136,  135, 230, 190, 179,  233, 150, 128,
    239,  188, 137,  239, 188, 140,  231,  156, 129, 231, 186,  167, 228, 186,
    186,  230, 176,  145, 230, 148,  191,  229, 186, 156, 229,  143, 151, 229,
    155,  189, 229,  138, 161, 233,  153,  162, 233, 162, 134,  229, 175, 188,
    239,  188, 140,  231, 137, 185,  229,  136, 165, 232, 161,  140, 230, 148,
    191,  229, 141,  128, 229, 137,  135,  230, 160, 185, 230,  147, 154, 228,
    184,  128, 229,  156, 139, 229,  133,  169, 229, 136, 182,  230, 148, 191,
    231,  173, 150,  229, 175, 166,  232,  161, 140, 233, 171,  152, 229, 186,
    166,  232, 135,  170, 230, 178,  187,  227, 128, 130, 229,  133, 168, 229,
    155,  189, 232,  183, 168, 232,  182,  138, 228, 186, 148,  228, 184, 170,
    229,  156, 176,  231, 144, 134,  230,  151, 182, 229, 140,  186, 239, 188,
    140,  228, 189,  134, 229, 157,  135,  228, 189, 191, 231,  148, 168, 228,
    184,  173, 229,  156, 139, 230,  168,  153, 230, 186, 150,  230, 153, 130,
    233,  150, 147,  239, 188, 136,  229,  141, 179, 'U', 'T',  'C', '+', '8',
    239,  188, 137,  227, 128, 130,  13,   10,  13,  10,  228,  184, 173, 232,
    143,  175, 228,  186, 186, 230,  176,  145, 229, 133, 177,  229, 146, 140,
    229,  156, 139,  230, 152, 175,  229,  164, 154, 230, 176,  145, 230, 151,
    143,  229, 155,  189, 229, 174,  182,  239, 188, 140, 229,  133, 182, 228,
    184,  173, 230,  177, 137, 230,  151,  143, 228, 189, 148,  231, 184, 189,
    228,  186, 186,  229, 143, 163,  231,  154, 132, '9', '1',  '.', '5', '9',
    '%',  239, 188,  140, 229, 133,  182,  233, 164, 152, '5',  '5', 228, 184,
    170,  230, 176,  145, 230, 151,  143,  231, 130, 186, 229,  176, 145, 230,
    149,  176, 230,  176, 145, 230,  151,  143, 239, 188, 140,  229, 155, 189,
    229,  174, 182,  232, 170, 141,  229,  174, 154, 231, 154,  132, '5', '6',
    229,  128, 139,  230, 176, 145,  230,  151, 143, 229, 144,  136, 231, 167,
    176,  226, 128,  156, 228, 184,  173,  229, 141, 142, 230,  176, 145, 230,
    151,  143, 226,  128, 157, 227,  128,  130, 228, 184, 173,  229, 141, 142,
    228,  186, 186,  230, 176, 145,  229,  133, 177, 229, 146,  140, 229, 155,
    189,  230, 156,  137, '2', '4',  231,  167, 141, 230, 176,  145, 230, 151,
    143,  230, 150,  135, 229, 173,  151,  239, 188, 140, 229,  133, 171, 229,
    141,  129, 229,  164, 154, 231,  167,  141, 230, 176, 145,  230, 151, 143,
    232,  175, 173,  232, 168, 128,  227,  128, 130, 228, 184,  173, 229, 141,
    142,  228, 186,  186, 230, 176,  145,  229, 133, 177, 229,  146, 140, 229,
    155,  189, 230,  178, 161, 230,  156,  137, 230, 152, 142,  231, 161, 174,
    232,  167, 132,  229, 174, 154,  231,  154, 132, 229, 155,  189, 229, 174,
    182,  232, 175,  173, 232, 168,  128,  239, 188, 140, 228,  187, 165, 230,
    177,  137, 232,  175, 173, 230,  153,  174, 233, 128, 154,  232, 175, 157,
    229,  146, 140,  232, 167, 132,  232,  140, 131, 231, 174,  128, 229, 140,
    150,  230, 177,  137, 229, 173,  151,  228, 184, 186, 226,  128, 156, 229,
    155,  189, 229,  174, 182, 233,  128,  154, 231, 148, 168,  232, 175, 173,
    232,  168, 128,  230, 150, 135,  229,  173, 151, 226, 128,  157, '[', 230,
    179,  168, ' ',  '5', ']', 227,  128,  130, 228, 184, 173,  229, 155, 189,
    228,  188, 160,  231, 187, 159,  228,  184, 138, 230, 152,  175, 228, 187,
    165,  231, 165,  150, 229, 133,  136,  228, 191, 161, 228,  187, 176, 228,
    184,  186, 228,  184, 187, 231,  154,  132, 229, 155, 189,  229, 174, 182,
    239,  188, 140,  229, 185, 182,  229,  133, 183, 230, 156,  137, 229, 132,
    146,  233, 135,  138, 233, 129,  147,  228, 184, 137, 230,  149, 153, 229,
    144,  136, 230,  181, 129, 231,  154,  132, 229, 174, 151,  230, 149, 153,
    228,  191, 161,  228, 187, 176,  228,  188, 160, 231, 187,  159, 229, 146,
    140,  231, 137,  185, 231, 130,  185,  239, 188, 140, 229,  144, 140, 230,
    151,  182, 229,  173, 152, 229,  156,  168, 229, 133, 182,  229, 174, 131,
    229,  164, 154,  231, 167, 141,  229,  174, 151, 230, 149,  153, 227, 128,
    130,  228, 184,  173, 229, 141,  142,  228, 186, 186, 230,  176, 145, 229,
    133,  177, 229,  146, 140, 229,  155,  189, 229, 144, 142,  239, 188, 140,
    229,  174, 152,  230, 150, 185,  229,  165, 137, 232, 161,  140, 230, 151,
    160,  231, 165,  158, 232, 174,  186,  239, 188, 140, 229,  133, 182, 229,
    144,  142, 230,  155, 190, 229,  143,  145, 229, 138, 168,  231, 154, 132,
    230,  150, 135,  229, 140, 150,  229,  164, 167, 233, 157,  169, 229, 145,
    189,  229, 175,  185, 229, 144,  132,  231, 167, 141, 229,  174, 151, 230,
    149,  153, 233,  128, 160, 230,  136,  144, 228, 184, 165,  233, 135, 141,
    231,  160, 180,  229, 157, 143,  239,  188, 140, 231, 155,  180, 229, 136,
    176,  230, 148,  185, 233, 157,  169,  229, 188, 128, 230,  148, 190, 229,
    144,  142, 230,  137, 141, 230,  156,  137, 230, 137, 128,  232, 189, 172,
    229,  143, 152,  227, 128, 130,  229,  189, 147, 228, 187,  138, 228, 184,
    173,  229, 155,  189, 230, 148,  191,  229, 186, 156, 229,  175, 185, 229,
    174,  151, 230,  149, 153, 228,  184,  142, 228, 188, 160,  231, 187, 159,
    228,  186, 139,  231, 137, 169,  233,  135, 135, 229, 143,  150, 228, 191,
    157,  230, 138,  164, 231, 154,  132,  230, 128, 129, 229,  186, 166, 227,
    128,  130, 13,   10,  13,  10,   228,  184, 173, 229, 141,  142, 228, 186,
    186,  230, 176,  145, 229, 133,  177,  229, 146, 140, 229,  155, 189, 230,
    152,  175, 229,  155, 189, 233,  153,  133, 231, 164, 190,  228, 188, 154,
    231,  154, 132,  233, 135, 141,  232,  166, 129, 228, 184,  128, 229, 145,
    152,  239, 188,  140, 228, 185,  159,  230, 152, 175, 228,  188, 151, 229,
    164,  154, 230,  173, 163, 229,  188,  143, 229, 146, 140,  233, 157, 158,
    230,  173, 163,  229, 188, 143,  231,  154, 132, 229, 164,  154, 232, 190,
    185,  231, 187,  132, 231, 187,  135,  231, 154, 132, 230,  136, 144, 229,
    145,  152, 239,  188, 140, 229,  140,  133, 230, 139, 172,  232, 129, 148,
    229,  144, 136,  229, 155, 189,  227,  128, 129, 228, 184,  150, 231, 149,
    140,  232, 180,  184, 230, 152,  147,  231, 187, 132, 231,  187, 135, 227,
    128,  129, 228,  186, 154, 229,  164,  170, 231, 187, 143,  229, 144, 136,
    231,  187, 132,  231, 187, 135,  227,  128, 129, 233, 135,  145, 231, 160,
    150,  229, 155,  155, 229, 155,  189,  227, 128, 129, 228,  184, 138, 230,
    181,  183, 229,  144, 136, 228,  189,  156, 231, 187, 132,  231, 187, 135,
    229,  146, 140,  '2', '0', 229,  155,  189, 233, 155, 134,  229, 155, 162,
    231,  173, 137,  239, 188, 140,  228,  184, 186, 232, 129,  148, 229, 144,
    136,  229, 155,  189, 229, 174,  137,  229, 133, 168, 231,  144, 134, 228,
    186,  139, 228,  188, 154, 229,  184,  184, 228, 187, 187,  231, 144, 134,
    228,  186, 139,  229, 155, 189,  227,  128, 129, 228, 184,  150, 231, 149,
    140,  231, 172,  172, 228, 186,  140,  229, 164, 167, 231,  187, 143, 230,
    181,  142, 228,  189, 147, 239,  188,  140, 230, 152, 175,  228, 184, 150,
    231,  149, 140,  231, 172, 172,  228,  184, 128, 229, 164,  167, 229, 135,
    186,  229, 143,  163, 229, 156,  139,  227, 128, 129, 228,  184, 150, 231,
    149,  140, 231,  172, 172, 228,  186,  140, 229, 164, 167,  233, 128, 178,
    229,  143, 163,  229, 156, 139,  239,  188, 140, 230, 147,  129, 230, 156,
    137,  230, 156,  128, 229, 164,  154,  231, 154, 132, 229,  164, 150, 230,
    177,  135, 229,  132, 178, 229,  130,  153, 239, 188, 140,  230, 156, 128,
    228,  184, 176,  229, 175, 140,  231,  154, 132, 228, 184,  150, 231, 149,
    140,  230, 150,  135, 229, 140,  150,  233, 129, 151, 228,  186, 167, 239,
    188,  140, 228,  186, 166, 230,  152,  175, 228, 184, 150,  231, 149, 140,
    228,  184, 138,  231, 187, 143,  230,  181, 142, 230, 136,  144, 233, 149,
    183,  230, 156,  128, 229, 191,  171,  231, 154, 132, 229,  156, 139, 229,
    174,  182, 228,  185, 139, 228,  184,  128, 227, 128, 130,  229, 143, 166,
    229,  164, 150,  239, 188, 140,  228,  184, 173, 229, 155,  189, 230, 139,
    165,  230, 156,  137, 228, 184,  150,  231, 149, 140, 228,  184, 138, 231,
    142,  176, 229,  189, 185, 229,  163,  171, 229, 133, 181,  230, 156, 128,
    229,  164, 154,  231, 154, 132,  229,  134, 155, 233, 152,  159, 239, 188,
    155,  229, 134,  155, 228, 186,  139,  229, 188, 128, 230,  148, 175, 228,
    184,  150, 231,  149, 140, 231,  172,  172, 228, 186, 140,  239, 188, 140,
    230,  139, 165,  230, 156, 137,  230,  160, 184, 230, 173,  166, 229, 153,
    168,  239, 188,  140, 229, 185,  182,  229, 133, 183, 229,  164, 135, 229,
    143,  145, 229,  176, 132, 229,  141,  171, 230, 152, 159,  227, 128, 129,
    232,  175, 149,  233, 170, 140,  229,  158, 139, 231, 169,  186, 233, 151,
    180,  231, 171,  153, 229, 146,  140,  230, 156, 136, 231,  144, 131, 229,
    143,  138, 230,  183, 177, 231,  169,  186, 230, 142, 162,  230, 181, 139,
    229,  153, 168,  231, 154, 132,  232,  131, 189, 229, 138,  155, 239, 188,
    155,  '2', '0',  '0', '3', 229,  185,  180, 239, 188, 140,  228, 184, 173,
    229,  155, 189,  230, 136, 144,  228,  184, 186, 228, 184,  150, 231, 149,
    140,  231, 172,  172, 228, 184,  137,  228, 184, 170, 232,  135, 170, 228,
    184,  187, 230,  136, 144, 229,  138,  159, 229, 143, 145,  229, 176, 132,
    232,  189, 189,  228, 186, 186,  232,  136, 170, 229, 164,  169, 229, 153,
    168,  231, 154,  132, 229, 155,  189,  229, 174, 182, 227,  128, 130, 228,
    184,  173, 229,  155, 189, 228,  186,  166, 230, 152, 175,  230, 189, 156,
    229,  156, 168,  232, 182, 133,  231,  186, 167, 229, 164,  167, 229, 155,
    189,  228, 185,  139, 228, 184,  128,  239, 188, 140, 232,  162, 171, 232,
    174,  164, 228,  184, 186, 230,  152,  175, 228, 184, 139,  228, 184, 128,
    228,  189, 141,  232, 182, 133,  231,  186, 167, 229, 164,  167, 229, 155,
    189,  231, 154,  132, 230, 156,  137,  229, 138, 155, 229,  128, 153, 233,
    128,  137, 228,  186, 186, 227,  128,  130, 13,  10,  13,   10,  228, 184,
    173,  229, 141,  142, 228, 186,  186,  230, 176, 145, 229,  133, 177, 229,
    146,  140, 229,  155, 189, 231,  154,  132, 230, 173, 163,  229, 188, 143,
    229,  155, 189,  229, 144, 141,  228,  186, 142, '1', '9',  '4', '9', 229,
    185,  180, 231,  148, 177, 228,  184,  173, 229, 156, 139,  228, 186, 186,
    230,  176, 145,  230, 148, 191,  230,  178, 187, 229, 141,  148, 229, 149,
    134,  230, 156,  131, 232, 173,  176,  231, 177, 140, 229,  130, 153, 230,
    156,  131, 232,  173, 176, 231,  162,  186, 229, 174, 154,  239, 188, 140,
    229,  189, 147,  229, 136, 157,  230,  155, 190, 229, 138,  160, 232, 168,
    187,  227, 128,  140, 231, 176,  161,  231, 168, 177, 239,  188, 154, 228,
    184,  173, 232,  143, 175, 230,  176,  145, 229, 156, 139,  227, 128, 141,
    239,  188, 140,  228, 189, 134,  229,  143, 184, 229, 190,  146, 231, 190,
    142,  229, 160,  130, 231, 173,  137,  230, 176, 145, 228,  184, 187, 229,
    133,  154, 230,  180, 190, 228,  186,  186, 229, 163, 171,  232, 174, 164,
    228,  184, 186,  230, 150, 176,  228,  184, 173, 229, 155,  189, 229, 186,
    148,  231, 161,  174, 231, 171,  139,  230, 150, 176, 229,  155, 189, 229,
    144,  141, 239,  188, 140, 228,  187,  165, 231, 164, 186,  228, 184, 164,
    230,  172, 161,  233, 157, 169,  229,  145, 189, 231, 154,  132, 230, 160,
    185,  230, 156,  172, 230, 132,  143,  228, 185, 137, 228,  184, 141, 229,
    144,  140, '[',  '1', '5', ']',  227,  128, 130, 229, 155,  160, 230, 173,
    164,  231, 155,  180, 232, 135,  179,  '9', 230, 156, 136,  '2', '7', 230,
    151,  165, 230,  148, 191, 229,  141,  148, 229, 133, 168,  233, 171, 148,
    230,  156, 131,  232, 173, 176,  232,  161, 168, 230, 177,  186, 233, 128,
    154,  233, 129,  142, 228, 184,  173,  229, 164, 174, 228,  186, 186, 230,
    176,  145, 230,  148, 191, 229,  186,  156, 231, 181, 132,  231, 185, 148,
    230,  179, 149,  230, 153, 130,  239,  188, 140, 230, 173,  163, 229, 188,
    143,  232, 173,  176, 230, 177,  186,  229, 142, 187, 233,  153, 164, 230,
    173,  164, 229,  138, 160, 232,  168,  187, '[', '1', '6',  ']', 227, 128,
    130,  13,  10,   13,  10,  229,  156,  168, 229, 133, 168,  233, 131, 168,
    229,  156, 139,  233, 154, 155,  229,  160, 180, 229, 144,  136, 239, 188,
    140,  228, 184,  173, 232, 143,  175,  228, 186, 186, 230,  176, 145, 229,
    133,  177, 229,  146, 140, 229,  156,  139, 228, 184, 128,  232, 136, 172,
    231,  176, 161,  231, 168, 177,  231,  130, 186, 228, 184,  173, 229, 156,
    139,  239, 188,  140, 230, 156,  137,  230, 151, 182, 229,  128, 153, 228,
    185,  159, 229,  155, 160, 229,  133,  182, 230, 137, 128,  229, 164, 132,
    229,  156, 176,  231, 144, 134,  228,  189, 141, 231, 189,  174, 232, 128,
    140,  232, 162,  171, 231, 167,  176,  228, 184, 186, 228,  184, 173, 229,
    155,  189, 229,  164, 167, 233,  153,  134, 227, 128, 130,  229, 156, 168,
    228,  184, 173,  229, 156, 139,  229,  156, 139, 229, 133,  167, 239, 188,
    140,  231, 149,  182, '1', '9',  '4',  '9', 229, 185, 180,  229, 137, 141,
    231,  154, 132,  228, 184, 173,  232,  143, 175, 230, 176,  145, 229, 156,
    139,  232, 136,  135, '1', '9',  '4',  '9', 229, 185, 180,  229, 190, 140,
    231,  154, 132,  228, 184, 173,  232,  143, 175, 228, 186,  186, 230, 176,
    145,  229, 133,  177, 229, 146,  140,  229, 156, 139, 229,  129, 154, 229,
    176,  141, 230,  175, 148, 230,  136,  150, 230, 156, 137,  230, 173, 164,
    230,  182, 181,  230, 140, 135,  230,  153, 130, 239, 188,  140, 229, 137,
    141,  232, 128,  133, 229, 184,  184,  232, 162, 171, 231,  168, 177, 231,
    130,  186, 232,  136, 138, 228,  184,  173, 229, 156, 139,  239, 188, 136,
    228,  186, 166,  231, 168, 177,  232,  136, 138, 231, 164,  190, 230, 156,
    131,  239, 188,  137, 239, 188,  140,  232, 128, 140, 229,  190, 140, 232,
    128,  133, 229,  137, 135, 229,  184,  184, 232, 162, 171,  231, 168, 177,
    231,  130, 186,  230, 150, 176,  228,  184, 173, 229, 156,  139, 227, 128,
    130,  231, 155,  174, 229, 137,  141,  239, 188, 140, 228,  184, 173, 232,
    143,  175, 228,  186, 186, 230,  176,  145, 229, 133, 177,  229, 146, 140,
    229,  156, 139,  232, 170, 141,  231,  130, 186, 228, 184,  173, 232, 143,
    175,  230, 176,  145, 229, 156,  139,  229, 183, 178, 232,  162, 171, 229,
    133,  182, 229,  143, 150, 228,  187,  163, 239, 188, 140,  228, 184, 173,
    232,  143, 175,  230, 176, 145,  229,  156, 139, 230, 148,  191, 229, 186,
    156,  229, 137,  135, 228, 184,  141,  230, 137, 191, 232,  170, 141, 228,
    184,  173, 232,  143, 175, 228,  186,  186, 230, 176, 145,  229, 133, 177,
    229,  146, 140,  229, 156, 139,  231,  154, 132, 230, 173,  163, 231, 181,
    177,  230, 128,  167, 239, 188,  140,  231, 149, 182, 229,  156, 168, 228,
    184,  173, 229,  156, 139, 229,  164,  167, 233, 153, 184,  231, 154, 132,
    228,  184, 173,  232, 143, 175,  228,  186, 186, 230, 176,  145, 229, 133,
    177,  229, 146,  140, 229, 156,  139,  230, 148, 191, 229,  186, 156, 232,
    136,  135, 229,  156, 168, 229,  143,  176, 231, 129, 163,  231, 154, 132,
    228,  184, 173,  232, 143, 175,  230,  176, 145, 229, 156,  139, 230, 148,
    191,  229, 186,  156, 229, 129,  154,  229, 176, 141, 230,  175, 148, 230,
    136,  150, 230,  156, 137, 230,  173,  164, 230, 182, 181,  230, 140, 135,
    230,  153, 130,  239, 188, 140,  229,  137, 141, 232, 128,  133, 229, 184,
    184,  232, 162,  171, 229, 190,  140,  232, 128, 133, 231,  168, 177, 231,
    130,  186, 229,  140, 151, 228,  186,  172, 231, 149, 182,  229, 177, 128,
    227,  128, 129,  229, 164, 167,  233,  153, 184, 231, 149,  182, 229, 177,
    128,  227, 128,  129, 228, 184,  173,  229, 133, 177, 231,  149, 182, 229,
    177,  128, 227,  128, 129, 228,  184,  173, 229, 156, 139,  229, 164, 167,
    233,  153, 184,  230, 136, 150,  229,  164, 167, 233, 153,  184, '[', '1',
    '7',  ']', 239,  188, 140, 229,  190,  140, 232, 128, 133,  229, 184, 184,
    232,  162, 171,  229, 137, 141,  232,  128, 133, 231, 168,  177, 231, 130,
    186,  229, 143,  176, 231, 129,  163,  231, 149, 182, 229,  177, 128, 227,
    128,  129, 229,  143, 176, 229,  140,  151, 231, 149, 182,  229, 177, 128,
    230,  136, 150,  229, 143, 176,  231,  129, 163, '[', '1',  '8', ']', 227,
    128,  130, 232,  136, 135, 230,  184,  175, 230, 190, 179,  229, 156, 176,
    229,  141, 128,  228, 184, 166,  231,  148, 168, 230, 153,  130, 229, 137,
    135,  231, 168,  177, 231, 130,  186,  228, 184, 173, 229,  156, 139, 229,
    133,  167, 229,  156, 176, 227,  128,  129, 229, 133, 167,  229, 156, 176,
    '[',  '1', '9',  ']', 227, 128,  130,  13,  10,  13,  10,   231, 149, 182,
    228,  184, 173,  229, 156, 139,  229,  164, 167, 233, 153,  184, 231, 154,
    132,  228, 184,  173, 232, 143,  175,  228, 186, 186, 230,  176, 145, 229,
    133,  177, 229,  146, 140, 229,  156,  139, 230, 148, 191,  229, 186, 156,
    232,  136, 135,  229, 156, 168,  229,  143, 176, 231, 129,  163, 231, 154,
    132,  228, 184,  173, 232, 143,  175,  230, 176, 145, 229,  156, 139, 230,
    148,  191, 229,  186, 156, 229,  129,  154, 229, 176, 141,  230, 175, 148,
    230,  136, 150,  229, 141, 128,  233,  154, 148, 228, 187,  139, 231, 180,
    185,  230, 153,  130, 239, 188,  140,  233, 128, 154, 229,  184, 184, 230,
    142,  161, 231,  148, 168, 229,  156,  176, 231, 144, 134,  229, 144, 141,
    232,  169, 158,  227, 128, 140,  228,  184, 173, 229, 156,  139, 229, 164,
    167,  233, 153,  184, 227, 128,  141,  239, 188, 136, 'C',  'h', 'i', 'n',
    'a',  ' ', 'M',  'a', 'i', 'n',  'l',  'a', 'n', 'd', 239,  188, 137, 230,
    136,  150, 228,  184, 173, 229,  155,  189, 239, 188, 136,  'C', 'h', 'i',
    'n',  'a', 239,  188, 137, 229,  129,  154, 231, 130, 186,  228, 184, 173,
    232,  143, 175,  228, 186, 186,  230,  176, 145, 229, 133,  177, 229, 146,
    140,  229, 156,  139, 231, 154,  132,  231, 176, 161, 231,  168, 177, 239,
    188,  140, 229,  176, 141, 230,  150,  188, 228, 184, 173,  232, 143, 175,
    230,  176, 145,  229, 156, 139,  229,  137, 135, 231, 176,  161, 231, 168,
    177,  231, 130,  186, 228, 184,  173,  232, 143, 175, 229,  143, 176, 229,
    140,  151, 239,  188, 136, 'C',  'h',  'i', 'n', 'e', 's',  'e', ' ', 'T',
    'a',  'i', 'p',  'e', 'i', 239,  188,  137, 230, 136, 150,  229, 143, 176,
    231,  129, 163,  239, 188, 136,  'T',  'a', 'i', 'w', 'a',  'n', 239, 188,
    137,  227, 128,  130, 232, 128,  140,  229, 143, 176, 230,  185, 190, 231,
    154,  132, 229,  170, 146, 228,  189,  147, 229, 137, 135,  229, 184, 184,
    228,  189, 191,  231, 148, 168,  227,  128, 140, 228, 184,  173, 229, 133,
    177,  227, 128,  141, 227, 128,  129,  227, 128, 140, 229,  164, 167, 233,
    153,  184, 229,  156, 176, 229,  141,  128, 227, 128, 141,  227, 128, 129,
    227,  128, 140,  229, 164, 167,  233,  153, 184, 227, 128,  141, 230, 136,
    150,  227, 128,  140, 228, 184,  173,  229, 155, 189, 227,  128, 141, 230,
    157,  165, 228,  189, 156, 231,  130,  186, 228, 184, 173,  232, 143, 175,
    228,  186, 186,  230, 176, 145,  229,  133, 177, 229, 146,  140, 229, 156,
    139,  231, 154,  132, 231, 176,  161,  231, 168, 177, 227,  128, 130, 233,
    166,  153, 230,  184, 175, 233,  131,  168, 229, 136, 134,  229, 170, 146,
    233,  171, 148,  228, 185, 159,  230,  156, 137, 228, 189,  191, 231, 148,
    168,  227, 128,  140, 228, 184,  173,  229, 156, 139, 227,  128, 141, 229,
    146,  140, 227,  128, 140, 228,  184,  173, 229, 133, 177,  227, 128, 141,
    228,  190, 134,  230, 140, 135,  228,  187, 163, 228, 184,  173, 229, 156,
    139,  229, 164,  167, 233, 153,  184,  227, 128, 130, 13,   10,  13,  10,
    '1',  '9', '4',  '9', 229, 185,  180,  239, 188, 140, 230,  173, 183, 230,
    153,  130, 228,  184, 137, 229,  185,  180, 231, 154, 132,  229, 156, 139,
    229,  133, 177,  229, 133, 167,  230,  136, 176, 228, 184,  187, 232, 166,
    129,  230, 136,  176, 229, 189,  185,  231, 181, 144, 230,  157, 159, 239,
    188,  140, 228,  184, 173, 229,  156,  139, 229, 133, 177,  231, 148, 162,
    233,  187, 168,  230, 137, 128,  233,  160, 152, 229, 176,  142, 231, 154,
    132,  228, 184,  173, 229, 156,  139,  228, 186, 186, 230,  176, 145, 232,
    167,  163, 230,  148, 190, 232,  187,  141, 230, 136, 176,  229, 139, 157,
    228,  186, 134,  228, 184, 173,  229,  156, 139, 229, 156,  139, 230, 176,
    145,  233, 187,  168, 230, 137,  128,  233, 160, 152, 229,  176, 142, 231,
    154,  132, 228,  184, 173, 232,  143,  175, 230, 176, 145,  229, 156, 139,
    229,  155, 189,  232, 187, 141,  '[',  230, 179, 168, ' ',  '6', ']', 239,
    188,  140, 228,  184, 166, 229,  183,  178, 233, 128, 144,  230, 188, 184,
    230,  142, 167,  229, 136, 182,  228,  186, 134, 228, 184,  173, 229, 156,
    139,  229, 164,  167, 233, 153,  184,  229, 164, 167, 233,  131, 168, 229,
    136,  134, 231,  156, 129, 228,  187,  189, 229, 146, 140,  229, 156, 176,
    229,  140, 186,  227, 128, 130,  13,   10,  13,  10,  229,  144, 140, 229,
    185,  180, '9',  230, 156, 136,  '2',  '1', 230, 151, 165,  232, 135, 179,
    '9',  230, 156,  136, '3', '0',  230,  151, 165, 239, 188,  140, 231, 182,
    147,  233, 129,  142, 230, 149,  184,  230, 156, 136, 231,  154, 132, 231,
    177,  140, 229,  130, 153, 239,  188,  140, 228, 184, 173,  229, 156, 139,
    228,  186, 186,  230, 176, 145,  230,  148, 191, 230, 178,  187, 229, 141,
    148,  229, 149,  134, 230, 156,  131,  232, 173, 176, 231,  172, 172, 228,
    184,  128, 229,  177, 134, 229,  133,  168, 233, 171, 148,  230, 156, 131,
    232,  173, 176,  229, 156, 168,  229,  140, 151, 229, 185,  179, 229, 143,
    172,  233, 150,  139, 227, 128,  130,  '9', 230, 156, 136,  '2', '1', 230,
    151,  165, 239,  188, 140, 228,  184,  173, 229, 156, 139,  228, 186, 186,
    230,  176, 145,  230, 148, 191,  230,  178, 187, 229, 141,  148, 229, 149,
    134,  230, 156,  131, 232, 173,  176,  231, 172, 172, 228,  184, 128, 229,
    177,  134, 229,  133, 168, 233,  171,  148, 230, 156, 131,  232, 173, 176,
    230,  173, 163,  229, 188, 143,  229,  174, 163, 229, 184,  131, 230, 136,
    144,  231, 171,  139, 228, 184,  173,  229, 141, 142, 228,  186, 186, 230,
    176,  145, 229,  133, 177, 229,  146,  140, 229, 155, 189,  '[', '2', '0',
    ']',  227, 128,  130, 228, 188,  154,  232, 174, 174, 233,  128, 154, 233,
    129,  142, 228,  186, 134, 227,  128,  138, 228, 184, 173,  229, 156, 139,
    228,  186, 186,  230, 176, 145,  230,  148, 191, 230, 178,  187, 229, 141,
    148,  229, 149,  134, 230, 156,  131,  232, 173, 176, 231,  181, 132, 231,
    185,  148, 230,  179, 149, 227,  128,  139, 227, 128, 129,  227, 128, 138,
    228,  184, 173,  232, 143, 175,  228,  186, 186, 230, 176,  145, 229, 133,
    177,  229, 146,  140, 229, 156,  139,  228, 184, 173, 229,  164, 174, 228,
    186,  186, 230,  176, 145, 230,  148,  191, 229, 186, 156,  231, 181, 132,
    231,  185, 148,  230, 179, 149,  227,  128, 139, 229, 146,  140, 229, 133,
    183,  230, 156,  137, 232, 135,  168,  230, 153, 130, 230,  134, 178, 230,
    179,  149, 230,  128, 167, 232,  179,  170, 231, 154, 132,  227, 128, 138,
    228,  184, 173,  229, 156, 139,  228,  186, 186, 230, 176,  145, 230, 148,
    191,  230, 178,  187, 229, 141,  148,  229, 149, 134, 230,  156, 131, 232,
    173,  176, 229,  133, 177, 229,  144,  140, 231, 182, 177,  233, 160, 152,
    227,  128, 139,  239, 188, 140,  230,  177, 186, 229, 174,  154, 228, 187,
    165,  229, 140,  151, 229, 185,  179,  231, 130, 186, 233,  166, 150, 233,
    131,  189, 228,  184, 166, 230,  148,  185, 229, 144, 141,  231, 136, 178,
    229,  140, 151,  228, 186, 172,  227,  128, 129, 228, 187,  165, 229, 133,
    172,  229, 133,  131, 231, 180,  128,  229, 185, 180, 227,  128, 129, 228,
    187,  165, 231,  190, 169, 229,  139,  135, 232, 187, 141,  233, 128, 178,
    232,  161, 140,  230, 155, 178,  231,  130, 186, 228, 187,  163, 229, 156,
    139,  230, 173,  140, 227, 128,  129,  228, 187, 165, 228,  186, 148, 230,
    152,  159, 231,  180, 133, 230,  151,  151, 231, 130, 186,  229, 156, 139,
    230,  151, 151,  239, 188, 140,  233,  128, 154, 233, 129,  142, 228, 186,
    134,  231, 148,  177, '1', '8',  '0',  228, 186, 186, 231,  181, 132, 230,
    136,  144, 231,  154, 132, 228,  184,  173, 229, 156, 139,  228, 186, 186,
    230,  176, 145,  230, 148, 191,  230,  178, 187, 229, 141,  148, 229, 149,
    134,  230, 156,  131, 232, 173,  176,  231, 172, 172, 228,  184, 128, 229,
    177,  134, 229,  133, 168, 229,  156,  139, 229, 167, 148,  229, 147, 161,
    230,  156, 131,  229, 144, 141,  229,  150, 174, 239, 188,  140, 228, 184,
    166,  233, 129,  184, 232, 136,  137,  230, 175, 155, 230,  190, 164, 230,
    157,  177, 231,  130, 186, 228,  184,  173, 229, 164, 174,  228, 186, 186,
    230,  176, 145,  230, 148, 191,  229,  186, 156, 228, 184,  187, 229, 184,
    173,  227, 128,  129, 230, 156,  177,  229, 190, 183, 227,  128, 129, 229,
    136,  152, 229,  176, 145, 229,  165,  135, 227, 128, 129,  229, 174, 139,
    229,  186, 134,  233, 190, 132,  227,  128, 129, 230, 157,  142, 230, 181,
    142,  230, 183,  177, 227, 128,  129,  229, 188, 160, 230,  190, 156, 227,
    128,  129, 233,  171, 152, 229,  178,  151, 231, 130, 186,  229, 137, 175,
    228,  184, 187,  229, 184, 173,  227,  128, 129, 229, 143,  166, 229, 164,
    150,  '5', '6',  228, 189, 141,  231,  130, 186, 228, 184,  173, 229, 164,
    174,  228, 186,  186, 230, 176,  145,  230, 148, 191, 229,  186, 156, 229,
    167,  148, 229,  147, 161, 227,  128,  130, '1', '0', 230,  156, 136, '1',
    230,  151, 165,  229, 188, 128,  229,  155, 189, 229, 164,  167, 229, 133,
    184,  229, 156,  168, 229, 140,  151,  228, 186, 172, 228,  184, 190, 232,
    161,  140, 239,  188, 140, 230,  175,  155, 230, 190, 164,  230, 157, 177,
    229,  156, 168,  229, 164, 169,  229,  174, 137, 233, 151,  168, 229, 159,
    142,  230, 165,  188, 229, 174,  163,  229, 145, 138, 228,  184, 173, 229,
    141,  142, 228,  186, 186, 230,  176,  145, 229, 133, 177,  229, 146, 140,
    229,  155, 189,  228, 184, 173,  229,  164, 174, 228, 186,  186, 230, 176,
    145,  230, 148,  191, 229, 186,  156,  230, 136, 144, 231,  171, 139, 239,
    188,  155, '1',  '2', 230, 156,  136,  '7', 230, 151, 165,  239, 188, 140,
    228,  184, 173,  232, 143, 175,  230,  176, 145, 229, 156,  139, 230, 148,
    191,  229, 186,  156, 230, 173,  163,  229, 188, 143, 231,  148, 177, 229,
    155,  155, 229,  183, 157, 231,  156,  129, 230, 136, 144,  233, 131, 189,
    229,  184, 130,  233, 129, 183,  229,  190, 128, 229, 143,  176, 230, 185,
    190,  231, 156,  129, 229, 143,  176,  229, 140, 151, 229,  184, 130, 239,
    188,  140, 228,  184, 166, 231,  185,  188, 231, 186, 140,  231, 181, 177,
    230,  178, 187,  229, 143, 176,  231,  129, 163, 230, 156,  172, 229, 179,
    182,  229, 143,  138, 230, 190,  142,  230, 185, 150, 227,  128, 129, 233,
    131,  168, 229,  136, 134, 231,  166,  143, 229, 187, 186,  233, 155, 162,
    229,  179, 182,  227, 128, 129,  228,  184, 156, 230, 178,  153, 231, 190,
    164,  229, 178,  155, 227, 128,  129,  229, 164, 170, 229,  185, 179, 229,
    178,  155, 231,  173, 137, 232,  135,  179, 228, 187, 138,  227, 128, 130,
    232,  135, 179,  230, 173, 164,  239,  188, 140, 228, 184,  173, 229, 156,
    139,  230, 173,  183, 229, 143,  178,  228, 184, 138, 230,  150, 188, 230,
    181,  183, 229,  179, 189, 229,  133,  169, 229, 178, 184,  229, 136, 134,
    230,  178, 187,  231, 154, 132,  230,  148, 191, 230, 178,  187, 230, 160,
    188,  229, 177,  128, 230, 173,  163,  229, 188, 143, 229,  189, 162, 230,
    136,  144, 227,  128, 130, 13,   10,   13,  10,  'H', 'i',  'n', 'd', 'i',
    ':',  13,  10,   13,  10,  224,  164,  173, 224, 164, 190,  224, 164, 176,
    224,  164, 164,  ',', ' ', 224,  164,  170, 224, 165, 140,  224, 164, 176,
    224,  164, 190,  224, 164, 163,  224,  164, 191, 224, 164,  149, ' ', 224,
    164,  156, 224,  164, 174, 224,  165,  141, 224, 164, 172,  224, 165, 130,
    224,  164, 166,  224, 165, 141,  224,  164, 181, 224, 165,  128, 224, 164,
    170,  ',', ' ',  224, 164, 134,  224,  164, 167, 224, 165,  129, 224, 164,
    168,  224, 164,  191, 224, 164,  149,  ' ', 224, 164, 166,  224, 164, 149,
    224,  165, 141,  224, 164, 183,  224,  164, 191, 224, 164,  163, ' ', 224,
    164,  143, 224,  164, 182, 224,  164,  191, 224, 164, 175,  224, 164, 190,
    ' ',  224, 164,  174, 224, 165,  135,  224, 164, 130, ' ',  224, 164, 184,
    224,  165, 141,  224, 164, 165,  224,  164, 191, 224, 164,  164, ' ', 224,
    164,  173, 224,  164, 190, 224,  164,  176, 224, 164, 164,  224, 165, 128,
    224,  164, 175,  ' ', 224, 164,  137,  224, 164, 170, 224,  164, 174, 224,
    164,  185, 224,  164, 190, 224,  164,  166, 224, 165, 141,  224, 164, 181,
    224,  165, 128,  224, 164, 170,  ' ',  224, 164, 149, 224,  164, 190, ' ',
    224,  164, 184,  224, 164, 172,  224,  164, 184, 224, 165,  135, ' ', 224,
    164,  172, 224,  164, 161, 224,  164,  188, 224, 164, 190,  ' ', 224, 164,
    166,  224, 165,  135, 224, 164,  182,  ' ', 224, 164, 185,  224, 165, 136,
    224,  165, 164,  ' ', 224, 164,  173,  224, 164, 190, 224,  164, 176, 224,
    164,  164, ' ',  224, 164, 149,  224,  164, 190, ' ', 224,  164, 173, 224,
    165,  140, 224,  164, 151, 224,  165,  139, 224, 164, 178,  224, 164, 191,
    224,  164, 149,  ' ', 224, 164,  171,  224, 165, 136, 224,  164, 178, 224,
    164,  190, 224,  164, 181, ' ',  224,  165, 174, 224, 165,  166, ' ', 224,
    165,  170, '\'', ' ', 224, 164,  184,  224, 165, 135, ' ',  224, 165, 169,
    224,  165, 173,  224, 165, 166,  ' ',  224, 165, 172, '\'', ' ', 224, 164,
    137,  224, 164,  164, 224, 165,  141,  224, 164, 164, 224,  164, 176, 224,
    165,  128, ' ',  224, 164, 133,  224,  164, 149, 224, 165,  141, 224, 164,
    183,  224, 164,  190, 224, 164,  130,  224, 164, 182, ' ',  224, 164, 164,
    224,  164, 149,  ' ', 224, 164,  164,  224, 164, 165, 224,  164, 190, ' ',
    224,  165, 172,  224, 165, 174,  224,  165, 166, ' ', 224,  165, 173, '\'',
    ' ',  224, 164,  184, 224, 165,  135,  ' ', 224, 165, 175,  224, 165, 173,
    224,  165, 166,  ' ', 224, 165,  168,  224, 165, 171, '\'', 224, 164, 170,
    224,  165, 130,  224, 164, 176,  224,  165, 141, 224, 164,  181, 224, 165,
    128,  ' ', 224,  164, 166, 224,  165,  135, 224, 164, 182,  224, 164, 190,
    224,  164, 168,  224, 165, 141,  224,  164, 164, 224, 164,  176, ' ', 224,
    164,  164, 224,  164, 149, ' ',  224,  164, 185, 224, 165,  136, 224, 165,
    164,  ' ', 224,  164, 173, 224,  164,  190, 224, 164, 176,  224, 164, 164,
    ' ',  224, 164,  149, 224, 164,  190,  ' ', 224, 164, 181,  224, 164, 191,
    224,  164, 184,  224, 165, 141,  224,  164, 164, 224, 164,  190, 224, 164,
    176,  ' ', 224,  164, 137, 224,  164,  164, 224, 165, 141,  224, 164, 164,
    224,  164, 176,  ' ', 224, 164,  184,  224, 165, 135, ' ',  224, 164, 166,
    224,  164, 149,  224, 165, 141,  224,  164, 183, 224, 164,  191, 224, 164,
    163,  ' ', 224,  164, 164, 224,  164,  149, ' ', 224, 164,  149, 224, 164,
    191,  '.', ' ',  224, 164, 174,  224,  165, 128, '.', ' ',  224, 164, 148,
    224,  164, 176,  ' ', 224, 164,  170,  224, 165, 130, 224,  164, 176, 224,
    165,  141, 224,  164, 181, ' ',  224,  164, 184, 224, 165,  135, ' ', 224,
    164,  170, 224,  164, 182, 224,  165,  141, 224, 164, 154,  224, 164, 191,
    224,  164, 174,  ' ', 224, 164,  164,  224, 164, 149, ' ',  224, 165, 168,
    ',',  224, 165,  175, 224, 165,  169,  224, 165, 169, ' ',  224, 164, 149,
    224,  164, 191,  '.', ' ', 224,  164,  174, 224, 165, 128,  '.', ' ', 224,
    164,  185, 224,  165, 136, 224,  165,  164, ' ', 224, 164,  173, 224, 164,
    190,  224, 164,  176, 224, 164,  164,  ' ', 224, 164, 149,  224, 165, 128,
    ' ',  224, 164,  184, 224, 164,  174,  224, 165, 129, 224,  164, 166, 224,
    165,  141, 224,  164, 176, ' ',  224,  164, 164, 224, 164,  159, ' ', 224,
    164,  176, 224,  165, 135, 224,  164,  150, 224, 164, 190,  ' ', 224, 165,
    173,  224, 165,  171, 224, 165,  167,  224, 165, 172, '.',  224, 165, 172,
    ' ',  224, 164,  149, 224, 164,  191,  224, 164, 178, 224,  165, 139, 224,
    164,  174, 224,  165, 128, 224,  164,  159, 224, 164, 176,  ' ', 224, 164,
    178,  224, 164,  174, 224, 165,  141,  224, 164, 172, 224,  165, 128, ' ',
    224,  164, 185,  224, 165, 136,  224,  165, 164, ' ', 224,  164, 173, 224,
    164,  190, 224,  164, 176, 224,  164,  164, ',', ' ', 224,  164, 173, 224,
    165,  140, 224,  164, 151, 224,  165,  139, 224, 164, 178,  224, 164, 191,
    224,  164, 149,  ' ', 224, 164,  166,  224, 165, 131, 224,  164, 183, 224,
    165,  141, 224,  164, 159, 224,  164,  191, ' ', 224, 164,  184, 224, 165,
    135,  ' ', 224,  164, 181, 224,  164,  191, 224, 164, 182,  224, 165, 141,
    224,  164, 181,  ' ', 224, 164,  174,  224, 165, 135, 224,  164, 130, ' ',
    224,  164, 184,  224, 164, 190,  224,  164, 164, 224, 164,  181, 224, 164,
    190,  224, 164,  129, ' ', 224,  164,  184, 224, 164, 172,  224, 164, 184,
    224,  165, 135,  ' ', 224, 164,  172,  224, 164, 161, 224,  164, 188, 224,
    164,  190, ' ',  224, 164, 148,  224,  164, 176, ' ', 224,  164, 156, 224,
    164,  168, 224,  164, 184, 224,  164,  129, 224, 164, 150,  224, 165, 141,
    224,  164, 175,  224, 164, 190,  ' ',  224, 164, 149, 224,  165, 135, ' ',
    224,  164, 166,  224, 165, 131,  224,  164, 183, 224, 165,  141, 224, 164,
    159,  224, 164,  191, 224, 164,  149,  224, 165, 139, 224,  164, 163, ' ',
    224,  164, 184,  224, 165, 135,  ' ',  224, 164, 166, 224,  165, 130, 224,
    164,  184, 224,  164, 176, 224,  164,  190, ' ', 224, 164,  184, 224, 164,
    172,  ' ', 224,  164, 184, 224,  165,  135, ' ', 224, 164,  172, 224, 164,
    161,  224, 164,  188, 224, 164,  190,  ' ', 224, 164, 166,  224, 165, 135,
    224,  164, 182,  ' ', 224, 164,  185,  224, 165, 136, 224,  165, 164, ' ',
    224,  164, 173,  224, 164, 190,  224,  164, 176, 224, 164,  164, ' ', 224,
    164,  149, 224,  165, 135, ' ',  224,  164, 170, 224, 164,  182, 224, 165,
    141,  224, 164,  154, 224, 164,  191,  224, 164, 174, ' ',  224, 164, 174,
    224,  165, 135,  224, 164, 130,  ' ',  224, 164, 170, 224,  164, 190, 224,
    164,  149, 224,  164, 191, 224,  164,  184, 224, 165, 141,  224, 164, 164,
    224,  164, 190,  224, 164, 168,  ',',  ' ', 224, 164, 137,  224, 164, 164,
    224,  165, 141,  224, 164, 164,  224,  164, 176, '-', 224,  164, 170, 224,
    165,  130, 224,  164, 176, 224,  165,  141, 224, 164, 181,  ' ', 224, 164,
    174,  224, 165,  135, 224, 164,  130,  ' ', 224, 164, 154,  224, 165, 128,
    224,  164, 168,  ',', ' ', 224,  164,  168, 224, 165, 135,  224, 164, 170,
    224,  164, 190,  224, 164, 178,  ',',  ' ', 224, 164, 148,  224, 164, 176,
    ' ',  224, 164,  173, 224, 165,  130,  224, 164, 159, 224,  164, 190, 224,
    164,  168, ' ',  224, 164, 148,  224,  164, 176, ' ', 224,  164, 170, 224,
    165,  130, 224,  164, 176, 224,  165,  141, 224, 164, 181,  ' ', 224, 164,
    174,  224, 165,  135, 224, 164,  130,  ' ', 224, 164, 172,  224, 164, 190,
    224,  164, 130,  224, 164, 151,  224,  165, 141, 224, 164,  178, 224, 164,
    190,  224, 164,  166, 224, 165,  135,  224, 164, 182, ' ',  224, 164, 148,
    224,  164, 176,  ' ', 224, 164,  174,  224, 165, 141, 224,  164, 175, 224,
    164,  190, 224,  164, 168, 224,  165,  141, 224, 164, 174,  224, 164, 190,
    224,  164, 176,  ' ', 224, 164,  166,  224, 165, 135, 224,  164, 182, ' ',
    224,  164, 184,  224, 165, 141,  224,  164, 165, 224, 164,  191, 224, 164,
    164,  ' ', 224,  164, 185, 224,  165,  136, 224, 164, 130,  224, 165, 164,
    ' ',  224, 164,  185, 224, 164,  191,  224, 164, 168, 224,  165, 141, 224,
    164,  166, ' ',  224, 164, 174,  224,  164, 185, 224, 164,  190, 224, 164,
    184,  224, 164,  190, 224, 164,  151,  224, 164, 176, ' ',  224, 164, 174,
    224,  165, 135,  224, 164, 130,  ' ',  224, 164, 135, 224,  164, 184, 224,
    164,  149, 224,  165, 135, ' ',  224,  164, 166, 224, 164,  149, 224, 165,
    141,  224, 164,  183, 224, 164,  191,  224, 164, 163, ' ',  224, 164, 170,
    224,  164, 182,  224, 165, 141,  224,  164, 154, 224, 164,  191, 224, 164,
    174,  ' ', 224,  164, 174, 224,  165,  135, 224, 164, 130,  ' ', 224, 164,
    174,  224, 164,  190, 224, 164,  178,  224, 164, 166, 224,  165, 128, 224,
    164,  181, ',',  ' ', 224, 164,  166,  224, 164, 149, 224,  165, 141, 224,
    164,  183, 224,  164, 191, 224,  164,  163, ' ', 224, 164,  174, 224, 165,
    135,  224, 164,  130, ' ', 224,  164,  182, 224, 165, 141,  224, 164, 176,
    224,  165, 128,  224, 164, 178,  224,  164, 130, 224, 164,  149, 224, 164,
    190,  ' ', 224,  164, 148, 224,  164,  176, ' ', 224, 164,  166, 224, 164,
    149,  224, 165,  141, 224, 164,  183,  224, 164, 191, 224,  164, 163, '-',
    224,  164, 170,  224, 165, 130,  224,  164, 176, 224, 165,  141, 224, 164,
    181,  ' ', 224,  164, 174, 224,  165,  135, 224, 164, 130,  ' ', 224, 164,
    135,  224, 164,  130, 224, 164,  161,  224, 165, 139, 224,  164, 168, 224,
    165,  135, 224,  164, 182, 224,  164,  191, 224, 164, 175,  224, 164, 190,
    ' ',  224, 164,  185, 224, 165,  136,  224, 164, 130, 224,  165, 164, ' ',
    224,  164, 137,  224, 164, 164,  224,  165, 141, 224, 164,  164, 224, 164,
    176,  '-', 224,  164, 170, 224,  164,  182, 224, 165, 141,  224, 164, 154,
    224,  164, 191,  224, 164, 174,  ' ',  224, 164, 174, 224,  165, 135, 224,
    164,  130, ' ',  224, 164, 133,  224,  164, 171, 224, 164,  188, 224, 164,
    151,  224, 164,  190, 224, 164,  168,  224, 164, 191, 224,  164, 184, 224,
    165,  141, 224,  164, 164, 224,  164,  190, 224, 164, 168,  ' ', 224, 164,
    149,  224, 165,  135, ' ', 224,  164,  184, 224, 164, 190,  224, 164, 165,
    ' ',  224, 164,  173, 224, 164,  190,  224, 164, 176, 224,  164, 164, ' ',
    224,  164, 149,  224, 165, 128,  ' ',  224, 164, 184, 224,  165, 128, 224,
    164,  174, 224,  164, 190, ' ',  224,  164, 185, 224, 165,  136, 224, 165,
    164,  ' ', 224,  164, 135, 224,  164,  184, 224, 164, 149,  224, 165, 135,
    ' ',  224, 164,  137, 224, 164,  164,  224, 165, 141, 224,  164, 164, 224,
    164,  176, ' ',  224, 164, 174,  224,  165, 135, 224, 164,  130, ' ', 224,
    164,  185, 224,  164, 191, 224,  164,  174, 224, 164, 190,  224, 164, 178,
    224,  164, 175,  ' ', 224, 164,  170,  224, 164, 176, 224,  165, 141, 224,
    164,  181, 224,  164, 164, ' ',  224,  164, 185, 224, 165,  136, ' ', 224,
    164,  148, 224,  164, 176, ' ',  224,  164, 166, 224, 164,  149, 224, 165,
    141,  224, 164,  183, 224, 164,  191,  224, 164, 163, ' ',  224, 164, 174,
    224,  165, 135,  224, 164, 130,  ' ',  224, 164, 185, 224,  164, 191, 224,
    164,  168, 224,  165, 141, 224,  164,  166, ' ', 224, 164,  174, 224, 164,
    185,  224, 164,  190, 224, 164,  184,  224, 164, 190, 224,  164, 151, 224,
    164,  176, ' ',  224, 164, 185,  224,  165, 136, 224, 165,  164, ' ', 224,
    164,  170, 224,  165, 130, 224,  164,  176, 224, 165, 141,  224, 164, 181,
    ' ',  224, 164,  174, 224, 165,  135,  224, 164, 130, ' ',  224, 164, 172,
    224,  164, 130,  224, 164, 151,  224,  164, 190, 224, 164,  178, ' ', 224,
    164,  149, 224,  165, 128, ' ',  224,  164, 150, 224, 164,  190, 224, 164,
    161,  224, 164,  188, 224, 165,  128,  ' ', 224, 164, 185,  224, 165, 136,
    ' ',  224, 164,  164, 224, 164,  165,  224, 164, 190, ' ',  224, 164, 170,
    224,  164, 182,  224, 165, 141,  224,  164, 154, 224, 164,  191, 224, 164,
    174,  ' ', 224,  164, 174, 224,  165,  135, 224, 164, 130,  ' ', 224, 164,
    133,  224, 164,  176, 224, 164,  172,  ' ', 224, 164, 184,  224, 164, 190,
    224,  164, 151,  224, 164, 176,  224,  164, 184, 224, 164,  174, 224, 165,
    129,  224, 164,  166, 224, 165,  141,  224, 164, 176, ' ',  224, 164, 185,
    224,  165, 136,  224, 164, 130,  ' ',  224, 165, 164, ' ',  224, 164, 173,
    224,  164, 190,  224, 164, 176,  224,  164, 164, ' ', 224,  164, 174, 224,
    165,  135, 224,  164, 130, ' ',  224,  164, 149, 224, 164,  136, ' ', 224,
    164,  172, 224,  164, 161, 224,  164,  188, 224, 165, 128,  ' ', 224, 164,
    168,  224, 164,  166, 224, 164,  191,  224, 164, 175, 224,  164, 190, 224,
    164,  129, ' ',  224, 164, 185,  224,  165, 136, 224, 164,  130, ' ', 224,
    165,  164, ' ',  224, 164, 151,  224,  164, 130, 224, 164,  151, 224, 164,
    190,  ' ', 224,  164, 168, 224,  164,  166, 224, 165, 128,  ' ', 224, 164,
    173,  224, 164,  190, 224, 164,  176,  224, 164, 164, 224,  165, 128, 224,
    164,  175, ' ',  224, 164, 184,  224,  164, 130, 224, 164,  184, 224, 165,
    141,  224, 164,  149, 224, 165,  131,  224, 164, 164, 224,  164, 191, ' ',
    224,  164, 174,  224, 165, 135,  224,  164, 130, ' ', 224,  164, 133, 224,
    164,  164, 224,  165, 141, 224,  164,  175, 224, 164, 130,  224, 164, 164,
    ' ',  224, 164,  170, 224, 164,  181,  224, 164, 191, 224,  164, 164, 224,
    165,  141, 224,  164, 176, ' ',  224,  164, 174, 224, 164,  190, 224, 164,
    168,  224, 165,  128, ' ', 224,  164,  156, 224, 164, 190,  224, 164, 164,
    224,  165, 128,  ' ', 224, 164,  185,  224, 165, 136, 224,  165, 164, ' ',
    224,  164, 133,  224, 164, 168,  224,  165, 141, 224, 164,  175, ' ', 224,
    164,  172, 224,  164, 161, 224,  164,  188, 224, 165, 128,  ' ', 224, 164,
    168,  224, 164,  166, 224, 164,  191,  224, 164, 175, 224,  164, 190, 224,
    164,  129, ' ',  224, 164, 184,  224,  164, 191, 224, 164,  168, 224, 165,
    141,  224, 164,  167, 224, 165,  129,  ',', ' ', 224, 164,  168, 224, 164,
    176,  224, 165,  141, 224, 164,  174,  224, 164, 166, 224,  164, 190, ',',
    ' ',  224, 164,  172, 224, 165,  141,  224, 164, 176, 224,  164, 185, 224,
    165,  141, 224,  164, 174, 224,  164,  170, 224, 165, 129,  224, 164, 164,
    224,  165, 141,  224, 164, 176,  ',',  ' ', 224, 164, 175,  224, 164, 174,
    224,  165, 129,  224, 164, 168,  224,  164, 190, ',', ' ',  224, 164, 151,
    224,  165, 139,  224, 164, 166,  224,  164, 190, 224, 164,  181, 224, 164,
    176,  224, 165,  128, ',', ' ',  224,  164, 149, 224, 164,  190, 224, 164,
    181,  224, 165,  135, 224, 164,  176,  224, 165, 128, ',',  ' ', 224, 164,
    149,  224, 165,  131, 224, 164,  183,  224, 165, 141, 224,  164, 163, 224,
    164,  190, ',',  ' ', 224, 164,  154,  224, 164, 174, 224,  165, 141, 224,
    164,  172, 224,  164, 178, ',',  ' ',  224, 164, 184, 224,  164, 164, 224,
    164,  178, 224,  164, 156, ',',  ' ',  224, 164, 181, 224,  165, 141, 224,
    164,  175, 224,  164, 190, 224,  164,  184, ' ', 224, 164,  134, 224, 164,
    166,  224, 164,  191, ' ', 224,  164,  185, 224, 165, 136,  224, 164, 130,
    224,  165, 164,  13,  10,  13,   10,   224, 164, 175, 224,  164, 185, ' ',
    224,  164, 181,  224, 164, 191,  224,  164, 182, 224, 165,  141, 224, 164,
    181,  ' ', 224,  164, 149, 224,  164,  190, ' ', 224, 164,  184, 224, 164,
    172,  224, 164,  184, 224, 165,  135,  ' ', 224, 164, 172,  224, 164, 161,
    224,  164, 188,  224, 164, 190,  ' ',  224, 164, 178, 224,  165, 139, 224,
    164,  149, 224,  164, 164, 224,  164,  130, 224, 164, 164,  224, 165, 141,
    224,  164, 176,  ' ', 224, 164,  185,  224, 165, 136, 224,  165, 164, ' ',
    224,  164, 175,  224, 164, 185,  224,  164, 190, 224, 164,  129, ' ', 224,
    165,  169, 224,  165, 166, 224,  165,  166, ' ', 224, 164,  184, 224, 165,
    135,  ' ', 224,  164, 133, 224,  164,  167, 224, 164, 191,  224, 164, 149,
    ' ',  224, 164,  173, 224, 164,  190,  224, 164, 183, 224,  164, 190, 224,
    164,  143, 224,  164, 129, ' ',  224,  164, 172, 224, 165,  139, 224, 164,
    178,  224, 165,  128, ' ', 224,  164,  156, 224, 164, 190,  224, 164, 164,
    224,  165, 128,  ' ', 224, 164,  185,  224, 165, 136, 224,  164, 130, ' ',
    '[',  '1', ']',  224, 165, 164,  ' ',  224, 164, 175, 224,  164, 185, ' ',
    224,  164, 181,  224, 164, 191,  224,  164, 182, 224, 165,  141, 224, 164,
    181,  ' ', 224,  164, 149, 224,  165,  128, ' ', 224, 164,  149, 224, 165,
    129,  224, 164,  155, ' ', 224,  164,  170, 224, 165, 141,  224, 164, 176,
    224,  164, 190,  224, 164, 154,  224,  165, 128, 224, 164,  168, 224, 164,
    164,  224, 164,  174, ' ', 224,  164,  184, 224, 164, 173,  224, 165, 141,
    224,  164, 175,  224, 164, 164,  224,  164, 190, 224, 164,  147, 224, 164,
    130,  ' ', 224,  164, 149, 224,  165,  128, ' ', 224, 164,  156, 224, 164,
    168,  224, 164,  168, 224, 165,  128,  ' ', 224, 164, 176,  224, 164, 185,
    224,  164, 190,  ' ', 224, 164,  185,  224, 165, 136, ' ',  224, 164, 156,
    224,  165, 136,  224, 164, 184,  224,  165, 135, ' ', '-',  ' ', 224, 164,
    184,  224, 164,  191, 224, 164,  168,  224, 165, 141, 224,  164, 167, 224,
    165,  129, ' ',  224, 164, 152,  224,  164, 190, 224, 164,  159, 224, 165,
    128,  ' ', 224,  164, 184, 224,  164,  173, 224, 165, 141,  224, 164, 175,
    224,  164, 164,  224, 164, 190,  ',',  ' ', 224, 164, 148,  224, 164, 176,
    ' ',  224, 164,  174, 224, 164,  185,  224, 164, 164, 224,  165, 141, 224,
    164,  181, 224,  164, 170, 224,  165,  130, 224, 164, 176,  224, 165, 141,
    224,  164, 163,  ' ', 224, 164,  144,  224, 164, 164, 224,  164, 191, 224,
    164,  185, 224,  164, 190, 224,  164,  184, 224, 164, 191,  224, 164, 149,
    ' ',  224, 164,  181, 224, 165,  141,  224, 164, 175, 224,  164, 190, 224,
    164,  170, 224,  164, 190, 224,  164,  176, ' ', 224, 164,  170, 224, 164,
    165,  224, 165,  139, 224, 164,  130,  ' ', 224, 164, 149,  224, 164, 190,
    ' ',  224, 164,  133, 224, 164,  173,  224, 164, 191, 224,  164, 168, 224,
    165,  141, 224,  164, 168, ' ',  224,  164, 133, 224, 164,  130, 224, 164,
    151,  ' ', 224,  164, 173, 224,  165,  128, '.', ' ', 224,  164, 181, 224,
    164,  191, 224,  164, 182, 224,  165,  141, 224, 164, 181,  ' ', 224, 164,
    149,  224, 165,  135, ' ', 224,  164,  154, 224, 164, 190,  224, 164, 176,
    ' ',  224, 164,  170, 224, 165,  141,  224, 164, 176, 224,  164, 174, 224,
    165,  129, 224,  164, 150, ' ',  224,  164, 167, 224, 164,  176, 224, 165,
    141,  224, 164,  174, ' ', ':',  ' ',  224, 164, 184, 224,  164, 168, 224,
    164,  190, 224,  164, 164, 224,  164,  168, '-', 224, 164,  185, 224, 164,
    191,  224, 164,  168, 224, 165,  141,  224, 164, 166, 224,  165, 130, ',',
    ' ',  224, 164,  172, 224, 165,  140,  224, 164, 166, 224,  165, 141, 224,
    164,  167, ',',  ' ', 224, 164,  156,  224, 165, 136, 224,  164, 168, ' ',
    224,  164, 164,  224, 164, 165,  224,  164, 190, ' ', 224,  164, 184, 224,
    164,  191, 224,  164, 150, ' ',  224,  164, 173, 224, 164,  190, 224, 164,
    176,  224, 164,  164, ' ', 224,  164,  174, 224, 165, 135,  224, 164, 130,
    ' ',  224, 164,  185, 224, 165,  128,  ' ', 224, 164, 156,  224, 164, 168,
    224,  165, 141,  224, 164, 174,  224,  165, 135, ' ', 224,  164, 148, 224,
    164,  176, ' ',  224, 164, 181,  224,  164, 191, 224, 164,  149, 224, 164,
    184,  224, 164,  191, 224, 164,  164,  ' ', 224, 164, 185,  224, 165, 129,
    224,  164, 143,  224, 165, 164,  13,   10,  13,  10,  224,  164, 173, 224,
    164,  190, 224,  164, 176, 224,  164,  164, ' ', 224, 164,  173, 224, 165,
    140,  224, 164,  151, 224, 165,  139,  224, 164, 178, 224,  164, 191, 224,
    164,  149, ' ',  224, 164, 149,  224,  165, 141, 224, 164,  183, 224, 165,
    135,  224, 164,  164, 224, 165,  141,  224, 164, 176, 224,  164, 171, 224,
    164,  178, ' ',  224, 164, 149,  224,  165, 135, ' ', 224,  164, 134, 224,
    164,  167, 224,  164, 190, 224,  164,  176, ' ', 224, 164,  170, 224, 164,
    176,  ' ', 224,  164, 181, 224,  164,  191, 224, 164, 182,  224, 165, 141,
    224,  164, 181,  ' ', 224, 164,  149,  224, 164, 190, ' ',  224, 164, 184,
    224,  164, 190,  224, 164, 164,  224,  164, 181, 224, 164,  190, 224, 164,
    129,  ' ', 224,  164, 184, 224,  164,  172, 224, 164, 184,  224, 165, 135,
    ' ',  224, 164,  172, 224, 164,  161,  224, 164, 188, 224,  164, 190, ' ',
    224,  164, 176,  224, 164, 190,  224,  164, 183, 224, 165,  141, 224, 164,
    159,  224, 165,  141, 224, 164,  176,  ' ', 224, 164, 185,  224, 165, 136,
    224,  165, 164,  ' ', 224, 164,  173,  224, 164, 190, 224,  164, 176, 224,
    164,  164, ' ',  224, 164, 149,  224,  165, 128, ' ', 224,  164, 176, 224,
    164,  190, 224,  164, 156, 224,  164,  167, 224, 164, 190,  224, 164, 168,
    224,  165, 128,  ' ', 224, 164,  168,  224, 164, 136, ' ',  224, 164, 166,
    224,  164, 191,  224, 164, 178,  224,  165, 141, 224, 164,  178, 224, 165,
    128,  ' ', 224,  164, 185, 224,  165,  136, 224, 165, 164,  ' ', 224, 164,
    173,  224, 164,  190, 224, 164,  176,  224, 164, 164, ' ',  224, 164, 149,
    224,  165, 135,  ' ', 224, 164,  133,  224, 164, 168, 224,  165, 141, 224,
    164,  175, ' ',  224, 164, 172,  224,  164, 161, 224, 164,  188, 224, 165,
    135,  ' ', 224,  164, 174, 224,  164,  185, 224, 164, 190,  224, 164, 168,
    224,  164, 151,  224, 164, 176,  ' ',  224, 164, 174, 224,  165, 129, 224,
    164,  174, 224,  165, 141, 224,  164,  172, 224, 164, 136,  ' ', '(', 224,
    164,  172, 224,  164, 174, 224,  165,  141, 224, 164, 172,  224, 164, 136,
    ')',  ',', ' ',  224, 164, 149,  224,  165, 139, 224, 164,  178, 224, 164,
    149,  224, 164,  190, 224, 164,  164,  224, 164, 190, ' ',  '(', 224, 164,
    149,  224, 164,  178, 224, 164,  149,  224, 164, 164, 224,  165, 141, 224,
    164,  164, 224,  164, 190, ')',  ' ',  224, 164, 148, 224,  164, 176, ' ',
    224,  164, 154,  224, 165, 135,  224,  164, 168, 224, 165,  141, 224, 164,
    168,  224, 164,  136, ' ', '(',  224,  164, 174, 224, 164,  166, 224, 165,
    141,  224, 164,  176, 224, 164,  190,  224, 164, 184, ')',  ' ', 224, 164,
    185,  224, 165,  136, 224, 164,  130,  224, 165, 164, ' ',  224, 165, 167,
    224,  165, 175,  224, 165, 170,  224,  165, 173, ' ', 224,  164, 174, 224,
    165,  135, 224,  164, 130, ' ',  224,  164, 184, 224, 165,  141, 224, 164,
    181,  224, 164,  164, 224, 164,  130,  224, 164, 164, 224,  165, 141, 224,
    164,  176, 224,  164, 164, 224,  164,  190, ' ', 224, 164,  170, 224, 165,
    141,  224, 164,  176, 224, 164,  190,  224, 164, 170, 224,  165, 141, 224,
    164,  164, 224,  164, 191, ' ',  224,  164, 184, 224, 165,  135, ' ', 224,
    164,  170, 224,  165, 130, 224,  164,  176, 224, 165, 141,  224, 164, 181,
    ' ',  224, 164,  172, 224, 165,  141,  224, 164, 176, 224,  164, 191, 224,
    164,  159, 224,  164, 191, 224,  164,  182, ' ', 224, 164,  173, 224, 164,
    190,  224, 164,  176, 224, 164,  164,  ' ', 224, 164, 149,  224, 165, 135,
    ' ',  224, 164,  176, 224, 165,  130,  224, 164, 170, ' ',  224, 164, 174,
    224,  165, 135,  224, 164, 130,  ' ',  224, 164, 172, 224,  165, 141, 224,
    164,  176, 224,  164, 191, 224,  164,  159, 224, 164, 191,  224, 164, 182,
    ' ',  224, 164,  184, 224, 164,  190,  224, 164, 174, 224,  165, 141, 224,
    164,  176, 224,  164, 190, 224,  164,  156, 224, 165, 141,  224, 164, 175,
    ' ',  224, 164,  149, 224, 165,  135,  ' ', 224, 164, 170,  224, 165, 141,
    224,  164, 176,  224, 164, 174,  224,  165, 129, 224, 164,  150, ' ', 224,
    164,  133, 224,  164, 130, 224,  164,  151, ' ', 224, 164,  173, 224, 164,
    190,  224, 164,  176, 224, 164,  164,  ' ', 224, 164, 168,  224, 165, 135,
    ' ',  224, 164,  181, 224, 164,  191,  224, 164, 151, 224,  164, 164, ' ',
    224,  165, 168,  224, 165, 166,  ' ',  224, 164, 181, 224,  164, 176, 224,
    165,  141, 224,  164, 183, ' ',  224,  164, 174, 224, 165,  135, 224, 164,
    130,  ' ', 224,  164, 184, 224,  164,  190, 224, 164, 176,  224, 165, 141,
    224,  164, 165,  224, 164, 149,  ' ',  224, 164, 170, 224,  165, 141, 224,
    164,  176, 224,  164, 151, 224,  164,  164, 224, 164, 191,  ' ', 224, 164,
    149,  224, 165,  128, ' ', 224,  164,  185, 224, 165, 136,  ',', ' ', 224,
    164,  181, 224,  164, 191, 224,  164,  182, 224, 165, 135,  224, 164, 183,
    ' ',  224, 164,  176, 224, 165,  130,  224, 164, 170, ' ',  224, 164, 184,
    224,  165, 135,  ' ', 224, 164,  134,  224, 164, 176, 224,  165, 141, 224,
    164,  165, 224,  164, 191, 224,  164,  149, ' ', 224, 164,  148, 224, 164,
    176,  ' ', 224,  164, 173, 224,  164,  190, 224, 164, 176,  224, 164, 164,
    224,  165, 128,  224, 164, 175,  ' ',  224, 164, 184, 224,  165, 135, 224,
    164,  168, 224,  164, 190, ' ',  224,  164, 143, 224, 164,  149, ' ', 224,
    164,  149, 224,  165, 141, 224,  164,  183, 224, 165, 135,  224, 164, 164,
    224,  165, 141,  224, 164, 176,  224,  165, 128, 224, 164,  175, ' ', 224,
    164,  182, 224,  164, 149, 224,  165,  141, 224, 164, 164,  224, 164, 191,
    ' ',  224, 164,  148, 224, 164,  176,  ' ', 224, 164, 181,  224, 164, 191,
    224,  164, 182,  224, 165, 141,  224,  164, 181, 224, 164,  181, 224, 165,
    141,  224, 164,  175, 224, 164,  190,  224, 164, 170, 224,  164, 149, ' ',
    224,  164, 182,  224, 164, 149,  224,  165, 141, 224, 164,  164, 224, 164,
    191,  ' ', 224,  164, 185, 224,  165,  136, 224, 165, 164,  ' ', 224, 164,
    173,  224, 164,  190, 224, 164,  176,  224, 164, 164, ' ',  224, 164, 181,
    224,  164, 191,  224, 164, 182,  224,  165, 141, 224, 164,  181, ' ', 224,
    164,  149, 224,  165, 128, ' ',  224,  164, 166, 224, 164,  184, 224, 164,
    181,  224, 165,  128, 224, 164,  130,  ' ', 224, 164, 184,  224, 164, 172,
    224,  164, 184,  224, 165, 135,  ' ',  224, 164, 172, 224,  164, 161, 224,
    164,  188, 224,  165, 128, ' ',  224,  164, 133, 224, 164,  176, 224, 165,
    141,  224, 164,  165, 224, 164,  181,  224, 165, 141, 224,  164, 175, 224,
    164,  181, 224,  164, 184, 224,  165,  141, 224, 164, 165,  224, 164, 190,
    ' ',  224, 164,  185, 224, 165,  136,  224, 165, 164, ' ',  224, 164, 185,
    224,  164, 190,  224, 164, 178,  ' ',  224, 164, 149, 224,  165, 135, ' ',
    224,  164, 181,  224, 164, 176,  224,  165, 141, 224, 164,  183, 224, 165,
    139,  224, 164,  130, ' ', 224,  164,  174, 224, 165, 135,  224, 164, 130,
    ' ',  224, 164,  173, 224, 164,  190,  224, 164, 176, 224,  164, 164, ' ',
    224,  164, 149,  224, 165, 128,  ' ',  224, 164, 133, 224,  164, 176, 224,
    165,  141, 224,  164, 165, 224,  164,  181, 224, 165, 141,  224, 164, 175,
    224,  164, 181,  224, 164, 184,  224,  165, 141, 224, 164,  165, 224, 164,
    190,  ' ', 224,  164, 168, 224,  165,  135, ' ', 224, 164,  172, 224, 164,
    185,  224, 165,  129, 224, 164,  164,  ' ', 224, 164, 170,  224, 165, 141,
    224,  164, 176,  224, 164, 151,  224,  164, 164, 224, 164,  191, ' ', 224,
    164,  149, 224,  165, 128, ' ',  224,  164, 185, 224, 165,  136, ',', ' ',
    224,  164, 148,  224, 164, 176,  ' ',  224, 164, 164, 224,  164, 190, 224,
    164,  156, 224,  164, 188, 224,  164,  190, ' ', 224, 164,  184, 224, 165,
    141,  224, 164,  165, 224, 164,  191,  224, 164, 164, 224,  164, 191, ' ',
    224,  164, 174,  224, 165, 135,  224,  164, 130, ' ', 224,  164, 173, 224,
    164,  190, 224,  164, 176, 224,  164,  164, ' ', 224, 164,  181, 224, 164,
    191,  224, 164,  182, 224, 165,  141,  224, 164, 181, ' ',  224, 164, 174,
    224,  165, 135,  224, 164, 130,  ' ',  224, 164, 164, 224,  165, 128, 224,
    164,  184, 224,  164, 176, 224,  165,  135, '-', 224, 164,  154, 224, 165,
    140,  224, 164,  165, 224, 165,  135,  ' ', 224, 164, 184,  224, 165, 141,
    224,  164, 165,  224, 164, 190,  224,  164, 168, ' ', 224,  164, 170, 224,
    164,  176, ' ',  224, 164, 185,  224,  165, 139, 224, 164,  168, 224, 165,
    135,  ' ', 224,  164, 149, 224,  164,  190, ' ', 224, 164,  166, 224, 164,
    190,  224, 164,  181, 224, 164,  190,  ' ', 224, 164, 149,  224, 164, 176,
    224,  164, 164,  224, 164, 190,  ' ',  224, 164, 185, 224,  165, 136, ' ',
    224,  165, 164,  13,  10,  13,   10,   224, 164, 173, 224,  164, 190, 224,
    164,  176, 224,  164, 164, ' ',  224,  164, 149, 224, 165,  135, ' ', 224,
    164,  166, 224,  165, 139, ' ',  224,  164, 134, 224, 164,  167, 224, 164,
    191,  224, 164,  149, 224, 164,  190,  224, 164, 176, 224,  164, 191, 224,
    164,  149, ' ',  224, 164, 168,  224,  164, 190, 224, 164,  174, ' ', 224,
    164,  185, 224,  165, 136, 224,  164,  130, '-', ' ', 224,  164, 185, 224,
    164,  191, 224,  164, 168, 224,  165,  141, 224, 164, 166,  224, 165, 128,
    ' ',  224, 164,  174, 224, 165,  135,  224, 164, 130, ' ',  224, 164, 173,
    224,  164, 190,  224, 164, 176,  224,  164, 164, ' ', 224,  164, 148, 224,
    164,  176, ' ',  224, 164, 133,  224,  164, 130, 224, 164,  151, 224, 165,
    141,  224, 164,  176, 224, 165,  135,  224, 164, 156, 224,  164, 188, 224,
    165,  128, ' ',  224, 164, 174,  224,  165, 135, 224, 164,  130, ' ', 224,
    164,  135, 224,  164, 163, 224,  165,  141, 224, 164, 161,  224, 164, 191,
    224,  164, 175,  224, 164, 190,  ' ',  '(', 'I', 'n', 'd',  'i', 'a', ')',
    224,  165, 164,  ' ', 224, 164,  135,  224, 164, 163, 224,  165, 141, 224,
    164,  161, 224,  164, 191, 224,  164,  175, 224, 164, 190,  ' ', 224, 164,
    168,  224, 164,  190, 224, 164,  174,  ' ', 224, 164, 149,  224, 165, 128,
    ' ',  224, 164,  137, 224, 164,  164,  224, 165, 141, 224,  164, 170, 224,
    164,  164, 224,  165, 141, 224,  164,  164, 224, 164, 191,  ' ', 224, 164,
    184,  224, 164,  191, 224, 164,  168,  224, 165, 141, 224,  164, 167, 224,
    165,  129, ' ',  224, 164, 168,  224,  164, 166, 224, 165,  128, ' ', 224,
    164,  149, 224,  165, 135, ' ',  224,  164, 133, 224, 164,  130, 224, 164,
    151,  224, 165,  141, 224, 164,  176,  224, 165, 135, 224,  164, 156, 224,
    165,  128, ' ',  224, 164, 168,  224,  164, 190, 224, 164,  174, ' ', '"',
    224,  164, 135,  224, 164, 163,  224,  165, 141, 224, 164,  161, 224, 164,
    184,  '"', ' ',  224, 164, 184,  224,  165, 135, ' ', 224,  164, 185, 224,
    165,  129, 224,  164, 136, ' ',  224,  164, 185, 224, 165,  136, 224, 165,
    164,  ' ', 224,  164, 173, 224,  164,  190, 224, 164, 176,  224, 164, 164,
    ' ',  224, 164,  168, 224, 164,  190,  224, 164, 174, ',',  ' ', 224, 164,
    143,  224, 164,  149, ' ', 224,  164,  170, 224, 165, 141,  224, 164, 176,
    224,  164, 190,  224, 164, 154,  224,  165, 128, 224, 164,  168, ' ', 224,
    164,  185, 224,  164, 191, 224,  164,  168, 224, 165, 141,  224, 164, 166,
    224,  165, 130,  ' ', 224, 164,  184,  224, 164, 174, 224,  165, 141, 224,
    164,  176, 224,  164, 190, 224,  164,  159, ' ', 224, 164,  173, 224, 164,
    176,  224, 164,  164, ' ', 224,  164,  156, 224, 165, 139,  ' ', 224, 164,
    149,  224, 164,  191, ' ', 224,  164,  174, 224, 164, 168,  224, 165, 129,
    ' ',  224, 164,  149, 224, 165,  135,  ' ', 224, 164, 181,  224, 164, 130,
    224,  164, 182,  224, 164, 156,  ' ',  224, 164, 139, 224,  164, 183, 224,
    164,  173, 224,  164, 166, 224,  165,  135, 224, 164, 181,  ' ', 224, 164,
    149,  224, 165,  135, ' ', 224,  164,  156, 224, 165, 141,  224, 164, 175,
    224,  165, 135,  224, 164, 183,  224,  165, 141, 224, 164,  160, ' ', 224,
    164,  170, 224,  165, 129, 224,  164,  164, 224, 165, 141,  224, 164, 176,
    ' ',  224, 164,  165, 224, 165,  135,  ' ', 224, 164, 164,  224, 164, 165,
    224,  164, 190,  ' ', 224, 164,  156,  224, 164, 191, 224,  164, 168, 224,
    164,  149, 224,  165, 128, ' ',  224,  164, 149, 224, 164,  165, 224, 164,
    190,  ' ', 224,  164, 182, 224,  165,  141, 224, 164, 176,  224, 165, 128,
    224,  164, 174,  224, 164, 166,  224,  165, 141, 224, 164,  173, 224, 164,
    190,  224, 164,  151, 224, 164,  181,  224, 164, 164, ' ',  224, 164, 174,
    224,  164, 185,  224, 164, 190,  224,  164, 170, 224, 165,  129, 224, 164,
    176,  224, 164,  190, 224, 164,  163,  ' ', 224, 164, 174,  224, 165, 135,
    224,  164, 130,  ' ', 224, 164,  185,  224, 165, 136, ',',  ' ', 224, 164,
    149,  224, 165,  135, ' ', 224,  164,  168, 224, 164, 190,  224, 164, 174,
    ' ',  224, 164,  184, 224, 165,  135,  ' ', 224, 164, 178,  224, 164, 191,
    224,  164, 175,  224, 164, 190,  ' ',  224, 164, 151, 224,  164, 175, 224,
    164,  190, ' ',  224, 164, 185,  224,  165, 136, 224, 165,  164, ' ', 224,
    164,  173, 224,  164, 190, 224,  164,  176, 224, 164, 164,  ' ', '(', 224,
    164,  173, 224,  164, 190, ' ',  '+',  ' ', 224, 164, 176,  224, 164, 164,
    ')',  ' ', 224,  164, 182, 224,  164,  172, 224, 165, 141,  224, 164, 166,
    ' ',  224, 164,  149, 224, 164,  190,  ' ', 224, 164, 174,  224, 164, 164,
    224,  164, 178,  224, 164, 172,  ' ',  224, 164, 185, 224,  165, 136, ' ',
    224,  164, 134,  224, 164, 168,  224,  165, 141, 224, 164,  164, 224, 164,
    176,  224, 164,  191, 224, 164,  149,  ' ', 224, 164, 170,  224, 165, 141,
    224,  164, 176,  224, 164, 149,  224,  164, 190, 224, 164,  182, ' ', 224,
    164,  175, 224,  164, 190, ' ',  224,  164, 181, 224, 164,  191, 224, 164,
    166,  224, 165,  135, 224, 164,  149,  '-', 224, 164, 176,  224, 165, 130,
    224,  164, 170,  224, 165, 128,  ' ',  224, 164, 170, 224,  165, 141, 224,
    164,  176, 224,  164, 149, 224,  164,  190, 224, 164, 182,  ' ', 224, 164,
    174,  224, 165,  135, 224, 164,  130,  ' ', 224, 164, 178,  224, 165, 128,
    224,  164, 168,  224, 165, 164,  ' ',  224, 164, 143, 224,  164, 149, ' ',
    224,  164, 164,  224, 165, 128,  224,  164, 184, 224, 164,  176, 224, 164,
    190,  ' ', 224,  164, 168, 224,  164,  190, 224, 164, 174,  ' ', 224, 164,
    185,  224, 164,  191, 224, 164,  168,  224, 165, 141, 224,  164, 166, 224,
    165,  129, 224,  164, 184, 224,  165,  141, 224, 164, 164,  224, 164, 190,
    224,  164, 168,  ' ', 224, 164,  173,  224, 165, 128, ' ',  224, 164, 185,
    224,  165, 136,  ' ', 224, 164,  156,  224, 164, 191, 224,  164, 184, 224,
    164,  149, 224,  164, 190, ' ',  224,  164, 133, 224, 164,  176, 224, 165,
    141,  224, 164,  165, ' ', 224,  164,  185, 224, 164, 191,  224, 164, 168,
    224,  165, 141,  224, 164, 166,  '(',  224, 164, 185, 224,  164, 191, 224,
    164,  168, 224,  165, 141, 224,  164,  166, 224, 165, 130,  ')', ' ', 224,
    164,  149, 224,  165, 128, ' ',  224,  164, 173, 224, 165,  130, 224, 164,
    174,  224, 164,  191, ' ', 224,  164,  185, 224, 165, 139,  224, 164, 164,
    224,  164, 190,  ' ', 224, 164,  185,  224, 165, 136, ' ',  224, 164, 156,
    224,  165, 139,  ' ', 224, 164,  149,  224, 164, 191, ' ',  224, 164, 170,
    224,  165, 141,  224, 164, 176,  224,  164, 190, 224, 164,  154, 224, 165,
    128,  224, 164,  168, ' ', 224,  164,  149, 224, 164, 190,  224, 164, 178,
    ' ',  224, 164,  139, 224, 164,  183,  224, 164, 191, 224,  164, 175, 224,
    165,  139, 224,  164, 130, ' ',  224,  164, 166, 224, 165,  141, 224, 164,
    181,  224, 164,  190, 224, 164,  176,  224, 164, 190, ' ',  224, 164, 166,
    224,  164, 191,  224, 164, 175,  224,  164, 190, ' ', 224,  164, 151, 224,
    164,  175, 224,  164, 190, ' ',  224,  164, 165, 224, 164,  190, 224, 165,
    164,  ' ', 224,  164, 170, 224,  165,  141, 224, 164, 176,  224, 164, 190,
    224,  164, 154,  224, 165, 128,  224,  164, 168, ' ', 224,  164, 149, 224,
    164,  190, 224,  164, 178, ' ',  224,  164, 174, 224, 165,  135, 224, 164,
    130,  ' ', 224,  164, 175, 224,  164,  185, ' ', 224, 164,  149, 224, 164,
    174,  ' ', 224,  164, 170, 224,  165,  141, 224, 164, 176,  224, 164, 175,
    224,  165, 129,  224, 164, 149,  224,  165, 141, 224, 164,  164, ' ', 224,
    164,  185, 224,  165, 139, 224,  164,  164, 224, 164, 190,  ' ', 224, 164,
    165,  224, 164,  190, ' ', 224,  164,  164, 224, 164, 165,  224, 164, 190,
    ' ',  224, 164,  149, 224, 164,  190,  224, 164, 178, 224,  164, 190, 224,
    164,  168, 224,  165, 141, 224,  164,  164, 224, 164, 176,  ' ', 224, 164,
    174,  224, 165,  135, 224, 164,  130,  ' ', 224, 164, 133,  224, 164, 167,
    224,  164, 191,  224, 164, 149,  ' ',  224, 164, 170, 224,  165, 141, 224,
    164,  176, 224,  164, 154, 224,  164,  178, 224, 164, 191,  224, 164, 164,
    ' ',  224, 164,  185, 224, 165,  129,  224, 164, 134, ' ',  224, 164, 181,
    224,  164, 191,  224, 164, 182,  224,  165, 135, 224, 164,  183, 224, 164,
    149,  224, 164,  176, ' ', 224,  164,  133, 224, 164, 176,  224, 164, 172,
    '/',  224, 164,  136, 224, 164,  176,  224, 164, 190, 224,  164, 168, ' ',
    224,  164, 174,  224, 165, 135,  224,  164, 130, 224, 165,  164, ' ', 224,
    164,  173, 224,  164, 190, 224,  164,  176, 224, 164, 164,  ' ', 224, 164,
    174,  224, 165,  135, 224, 164,  130,  ' ', 224, 164, 175,  224, 164, 185,
    ' ',  224, 164,  168, 224, 164,  190,  224, 164, 174, ' ',  224, 164, 174,
    224,  165, 129,  224, 164, 151,  224,  164, 178, ' ', 224,  164, 149, 224,
    164,  190, 224,  164, 178, ' ',  224,  164, 184, 224, 165,  135, ' ', 224,
    164,  133, 224,  164, 167, 224,  164,  191, 224, 164, 149,  ' ', 224, 164,
    170,  224, 165,  141, 224, 164,  176,  224, 164, 154, 224,  164, 178, 224,
    164,  191, 224,  164, 164, ' ',  224,  164, 185, 224, 165,  129, 224, 164,
    134,  ' ', 224,  164, 175, 224,  164,  166, 224, 165, 141,  224, 164, 175,
    224,  164, 170,  224, 164, 191,  ' ',  224, 164, 135, 224,  164, 184, 224,
    164,  149, 224,  164, 190, ' ',  224,  164, 184, 224, 164,  174, 224, 164,
    149,  224, 164,  190, 224, 164,  178,  224, 165, 128, 224,  164, 168, ' ',
    224,  164, 137,  224, 164, 170,  224,  164, 175, 224, 165,  139, 224, 164,
    151,  ' ', 224,  164, 149, 224,  164,  174, ' ', 224, 164,  148, 224, 164,
    176,  ' ', 224,  164, 170, 224,  165,  141, 224, 164, 176,  224, 164, 190,
    224,  164, 175,  224, 164, 131,  ' ',  224, 164, 137, 224,  164, 164, 224,
    165,  141, 224,  164, 164, 224,  164,  176, 224, 165, 128,  ' ', 224, 164,
    173,  224, 164,  190, 224, 164,  176,  224, 164, 164, ' ',  224, 164, 149,
    224,  165, 135,  ' ', 224, 164,  178,  224, 164, 191, 224,  164, 143, ' ',
    224,  164, 185,  224, 165, 139,  224,  164, 164, 224, 164,  190, ' ', 224,
    164,  185, 224,  165, 136, 224,  165,  164, ' ', 224, 164,  135, 224, 164,
    184,  224, 164,  149, 224, 165,  135,  ' ', 224, 164, 133,  224, 164, 164,
    224,  164, 191,  224, 164, 176,  224,  164, 191, 224, 164,  149, 224, 165,
    141,  224, 164,  164, ' ', 224,  164,  173, 224, 164, 190,  224, 164, 176,
    224,  164, 164,  224, 164, 181,  224,  164, 176, 224, 165,  141, 224, 164,
    183,  ' ', 224,  164, 149, 224,  165,  139, ' ', 224, 164,  181, 224, 165,
    136,  224, 164,  166, 224, 164,  191,  224, 164, 149, ' ',  224, 164, 149,
    224,  164, 190,  224, 164, 178,  ' ',  224, 164, 184, 224,  165, 135, ' ',
    224,  164, 134,  224, 164, 176,  224,  165, 141, 224, 164,  175, 224, 164,
    190,  224, 164,  181, 224, 164,  176,  224, 165, 141, 224,  164, 164, ' ',
    '"',  224, 164,  156, 224, 164,  174,  224, 165, 141, 224,  164, 172, 224,
    165,  130, 224,  164, 166, 224,  165,  141, 224, 164, 181,  224, 165, 128,
    224,  164, 170,  '"', ' ', 224,  164,  148, 224, 164, 176,  ' ', '"', 224,
    164,  133, 224,  164, 156, 224,  164,  168, 224, 164, 190,  224, 164, 173,
    224,  164, 166,  224, 165, 135,  224,  164, 182, '"', ' ',  224, 164, 149,
    224,  165, 135,  ' ', 224, 164,  168,  224, 164, 190, 224,  164, 174, ' ',
    224,  164, 184,  224, 165, 135,  ' ',  224, 164, 173, 224,  165, 128, ' ',
    224,  164, 156,  224, 164, 190,  224,  164, 168, 224, 164,  190, ' ', 224,
    164,  156, 224,  164, 190, 224,  164,  164, 224, 164, 190,  ' ', 224, 164,
    176,  224, 164,  185, 224, 164,  190,  ' ', 224, 164, 185,  224, 165, 136,
    224,  165, 164,  ' ', 224, 164,  172,  224, 164, 185, 224,  165, 129, 224,
    164,  164, ' ',  224, 164, 170,  224,  164, 185, 224, 164,  178, 224, 165,
    135,  ' ', 224,  164, 175, 224,  164,  185, ' ', 224, 164,  166, 224, 165,
    135,  224, 164,  182, ' ', '\'', 224,  164, 184, 224, 165,  139, 224, 164,
    168,  224, 165,  135, ' ', 224,  164,  149, 224, 165, 128,  ' ', 224, 164,
    154,  224, 164,  191, 224, 164,  161,  224, 164, 188, 224,  164, 191, 224,
    164,  175, 224,  164, 190, '\'', ' ',  224, 164, 149, 224,  165, 135, ' ',
    224,  164, 176,  224, 165, 130,  224,  164, 170, ' ', 224,  164, 174, 224,
    165,  135, 224,  164, 130, ' ',  224,  164, 156, 224, 164,  190, 224, 164,
    168,  224, 164,  190, ' ', 224,  164,  156, 224, 164, 190,  224, 164, 164,
    224,  164, 190,  ' ', 224, 164,  165,  224, 164, 190, 224,  165, 164, '[',
    '2',  ']', 13,   10,  13,  10,   'F',  'r', 'e', 'n', 'c',  'h', ':', 13,
    10,   13,  10,   'L', 'a', ' ',  'F',  'r', 'a', 'n', 'c',  'e', ',', ' ',
    'e',  'n', ' ',  'f', 'o', 'r',  'm',  'e', ' ', 'l', 'o',  'n', 'g', 'u',
    'e',  ' ', 'l',  'a', ' ', 'R',  195,  169, 'p', 'u', 'b',  'l', 'i', 'q',
    'u',  'e', ' ',  'f', 'r', 'a',  'n',  195, 167, 'a', 'i',  's', 'e', ',',
    ' ',  'e', 's',  't', ' ', 'u',  'n',  'e', ' ', 'r', 195,  169, 'p', 'u',
    'b',  'l', 'i',  'q', 'u', 'e',  ' ',  'c', 'o', 'n', 's',  't', 'i', 't',
    'u',  't', 'i',  'o', 'n', 'n',  'e',  'l', 'l', 'e', ' ',  'u', 'n', 'i',
    't',  'a', 'i',  'r', 'e', ' ',  'd',  'o', 'n', 't', ' ',  'l', 'a', ' ',
    'm',  'a', 'j',  'e', 'u', 'r',  'e',  ' ', 'p', 'a', 'r',  't', 'i', 'e',
    ' ',  'd', 'u',  ' ', 't', 'e',  'r',  'r', 'i', 't', 'o',  'i', 'r', 'e',
    ' ',  'e', 't',  ' ', 'd', 'e',  ' ',  'l', 'a', ' ', 'p',  'o', 'p', 'u',
    'l',  'a', 't',  'i', 'o', 'n',  ' ',  's', 'o', 'n', 't',  ' ', 's', 'i',
    't',  'u', 195,  169, 's', ' ',  'e',  'n', ' ', 'E', 'u',  'r', 'o', 'p',
    'e',  ' ', 'o',  'c', 'c', 'i',  'd',  'e', 'n', 't', 'a',  'l', 'e', ',',
    ' ',  'm', 'a',  'i', 's', ' ',  'q',  'u', 'i', ' ', 'c',  'o', 'm', 'p',
    'r',  'e', 'n',  'd', ' ', 195,  169,  'g', 'a', 'l', 'e',  'm', 'e', 'n',
    't',  ' ', 'p',  'l', 'u', 's',  'i',  'e', 'u', 'r', 's',  ' ', 'r', 195,
    169,  'g', 'i',  'o', 'n', 's',  ' ',  'e', 't', ' ', 't',  'e', 'r', 'r',
    'i',  't', 'o',  'i', 'r', 'e',  's',  ' ', 'r', 195, 169,  'p', 'a', 'r',
    't',  'i', 's',  ' ', 'd', 'a',  'n',  's', ' ', 'l', 'e',  's', ' ', 'A',
    'm',  195, 169,  'r', 'i', 'q',  'u',  'e', 's', ',', ' ',  'l', 226, 128,
    153,  'o', 'c',  195, 169, 'a',  'n',  ' ', 'I', 'n', 'd',  'i', 'e', 'n',
    ' ',  'e', 't',  ' ', 'l', '\'', 'o',  'c', 195, 169, 'a',  'n', ' ', 'P',
    'a',  'c', 'i',  'f', 'i', 'q',  'u',  'e', '.', ' ', 'E',  'l', 'l', 'e',
    ' ',  'a', ' ',  'p', 'o', 'u',  'r',  ' ', 'c', 'a', 'p',  'i', 't', 'a',
    'l',  'e', ' ',  'P', 'a', 'r',  'i',  's', ',', ' ', 'p',  'o', 'u', 'r',
    ' ',  'l', 'a',  'n', 'g', 'u',  'e',  ' ', 'o', 'f', 'f',  'i', 'c', 'i',
    'e',  'l', 'l',  'e', ' ', 'l',  'e',  ' ', 'f', 'r', 'a',  'n', 195, 167,
    'a',  'i', 's',  ' ', 'e', 't',  ' ',  'p', 'o', 'u', 'r',  ' ', 'm', 'o',
    'n',  'n', 'a',  'i', 'e', ' ',  'l',  226, 128, 153, 'e',  'u', 'r', 'o',
    '.',  ' ', 'S',  'a', ' ', 'd',  'e',  'v', 'i', 's', 'e',  ' ', 'e', 's',
    't',  ' ', 194,  171, ' ', 'L',  'i',  'b', 'e', 'r', 't',  195, 169, ',',
    ' ',  195, 137,  'g', 'a', 'l',  'i',  't', 195, 169, ',',  ' ', 'F', 'r',
    'a',  't', 'e',  'r', 'n', 'i',  't',  195, 169, ' ', 194,  187, ',', ' ',
    'e',  't', ' ',  's', 'o', 'n',  ' ',  'd', 'r', 'a', 'p',  'e', 'a', 'u',
    ' ',  'e', 's',  't', ' ', 'c',  'o',  'n', 's', 't', 'i',  't', 'u', 195,
    169,  ' ', 'd',  'e', ' ', 't',  'r',  'o', 'i', 's', ' ',  'b', 'a', 'n',
    'd',  'e', 's',  ' ', 'v', 'e',  'r',  't', 'i', 'c', 'a',  'l', 'e', 's',
    ' ',  'r', 'e',  's', 'p', 'e',  'c',  't', 'i', 'v', 'e',  'm', 'e', 'n',
    't',  ' ', 'b',  'l', 'e', 'u',  'e',  ',', ' ', 'b', 'l',  'a', 'n', 'c',
    'h',  'e', ' ',  'e', 't', ' ',  'r',  'o', 'u', 'g', 'e',  '.', ' ', 'S',
    'o',  'n', ' ',  'h', 'y', 'm',  'n',  'e', ' ', 'e', 's',  't', ' ', 'L',
    'a',  ' ', 'M',  'a', 'r', 's',  'e',  'i', 'l', 'l', 'a',  'i', 's', 'e',
    '.',  ' ', 'S',  'o', 'n', ' ',  'p',  'r', 'i', 'n', 'c',  'i', 'p', 'e',
    ' ',  'e', 's',  't', ' ', 'g',  'o',  'u', 'v', 'e', 'r',  'n', 'e', 'm',
    'e',  'n', 't',  ' ', 'd', 'u',  ' ',  'p', 'e', 'u', 'p',  'l', 'e', ',',
    ' ',  'p', 'a',  'r', ' ', 'l',  'e',  ' ', 'p', 'e', 'u',  'p', 'l', 'e',
    ' ',  'e', 't',  ' ', 'p', 'o',  'u',  'r', ' ', 'l', 'e',  ' ', 'p', 'e',
    'u',  'p', 'l',  'e', '[', '3',  ']',  '.', 13,  10,  13,   10,  'L', 'a',
    ' ',  'F', 'r',  'a', 'n', 'c',  'e',  ' ', 'e', 's', 't',  ' ', 'u', 'n',
    ' ',  'p', 'a',  'y', 's', ' ',  'a',  'n', 'c', 'i', 'e',  'n', ',', ' ',
    'f',  'o', 'r',  'm', 195, 169,  ' ',  'a', 'u', ' ', 'H',  'a', 'u', 't',
    ' ',  'M', 'o',  'y', 'e', 'n',  ' ',  195, 130, 'g', 'e',  '.', ' ', 'A',
    'u',  ' ', 'X',  'I', 'X', 'e',  ' ',  's', 'i', 195, 168,  'c', 'l', 'e',
    ' ',  'e', 't',  ' ', 'd', 'a',  'n',  's', ' ', 'l', 'a',  ' ', 'p', 'r',
    'e',  'm', 'i',  195, 168, 'r',  'e',  ' ', 'm', 'o', 'i',  't', 'i', 195,
    169,  ' ', 'd',  'u', ' ', 'X',  'X',  'e', ' ', 's', 'i',  195, 168, 'c',
    'l',  'e', ',',  ' ', 'e', 'l',  'l',  'e', ' ', 'p', 'o',  's', 's', 195,
    168,  'd', 'e',  ' ', 'u', 'n',  ' ',  'v', 'a', 's', 't',  'e', ' ', 'e',
    'm',  'p', 'i',  'r', 'e', ' ',  'c',  'o', 'l', 'o', 'n',  'i', 'a', 'l',
    '.',  ' ', 195,  128, ' ', 'p',  'a',  'r', 't', 'i', 'r',  ' ', 'd', 'e',
    's',  ' ', 'a',  'n', 'n', 195,  169,  'e', 's', ' ', '1',  '9', '5', '0',
    ',',  ' ', 'e',  'l', 'l', 'e',  ' ',  'e', 's', 't', ' ',  'l', 226, 128,
    153,  'u', 'n',  ' ', 'd', 'e',  's',  ' ', 'a', 'c', 't',  'e', 'u', 'r',
    's',  ' ', 'd',  'e', ' ', 'l',  'a',  ' ', 'c', 'o', 'n',  's', 't', 'r',
    'u',  'c', 't',  'i', 'o', 'n',  ' ',  'd', 'e', ' ', 'l',  226, 128, 153,
    'U',  'n', 'i',  'o', 'n', ' ',  'e',  'u', 'r', 'o', 'p',  195, 169, 'e',
    'n',  'n', 'e',  '.', ' ', 'E',  'l',  'l', 'e', ' ', 'e',  's', 't', ' ',
    'u',  'n', 'e',  ' ', 'p', 'u',  'i',  's', 's', 'a', 'n',  'c', 'e', ' ',
    'n',  'u', 'c',  'l', 195, 169,  'a',  'i', 'r', 'e', ',',  ' ', 'e', 't',
    ' ',  'l', 226,  128, 153, 'u',  'n',  ' ', 'd', 'e', 's',  ' ', 'c', 'i',
    'n',  'q', ' ',  'm', 'e', 'm',  'b',  'r', 'e', 's', ' ',  'p', 'e', 'r',
    'm',  'a', 'n',  'e', 'n', 't',  's',  ' ', 'd', 'u', ' ',  'C', 'o', 'n',
    's',  'e', 'i',  'l', ' ', 'd',  'e',  ' ', 's', 195, 169,  'c', 'u', 'r',
    'i',  't', 195,  169, ' ', 'd',  'e',  's', ' ', 'N', 'a',  't', 'i', 'o',
    'n',  's', ' ',  'u', 'n', 'i',  'e',  's', '.', ' ', 'L',  'a', ' ', 'F',
    'r',  'a', 'n',  'c', 'e', ' ',  'j',  'o', 'u', 'e', ' ',  'u', 'n', ' ',
    'r',  195, 180,  'l', 'e', ' ',  'i',  'm', 'p', 'o', 'r',  't', 'a', 'n',
    't',  ' ', 'd',  'a', 'n', 's',  ' ',  'l', 226, 128, 153,  'h', 'i', 's',
    't',  'o', 'i',  'r', 'e', ' ',  'm',  'o', 'n', 'd', 'i',  'a', 'l', 'e',
    ' ',  'p', 'a',  'r', ' ', 'l',  226,  128, 153, 'i', 'n',  'f', 'l', 'u',
    'e',  'n', 'c',  'e', ' ', 'd',  'e',  ' ', 's', 'a', ' ',  'c', 'u', 'l',
    't',  'u', 'r',  'e', ' ', 'e',  't',  ' ', 'd', 'e', ' ',  's', 'e', 's',
    ' ',  'v', 'a',  'l', 'e', 'u',  'r',  's', ' ', 'd', 195,  169, 'm', 'o',
    'c',  'r', 'a',  't', 'i', 'q',  'u',  'e', 's', ',', ' ',  'l', 'a', 195,
    175,  'q', 'u',  'e', 's', ' ',  'e',  't', ' ', 'r', 195,  169, 'p', 'u',
    'b',  'l', 'i',  'c', 'a', 'i',  'n',  'e', 's', '.', 13,   10,  13,  10,
    'L',  'a', ' ',  'F', 'r', 'a',  'n',  'c', 'e', ' ', 'a',  ',', ' ', 'e',
    'n',  ' ', '2',  '0', '1', '0',  ',',  ' ', 'l', 'e', ' ',  'c', 'i', 'n',
    'q',  'u', 'i',  195, 168, 'm',  'e',  ' ', 'p', 'l', 'u',  's', ' ', 'i',
    'm',  'p', 'o',  'r', 't', 'a',  'n',  't', ' ', 'p', 'r',  'o', 'd', 'u',
    'i',  't', ' ',  'i', 'n', 't',  195,  169, 'r', 'i', 'e',  'u', 'r', ' ',
    'b',  'r', 'u',  't', ' ', 'a',  'u',  ' ', 'm', 'o', 'n',  'd', 'e', '.',
    ' ',  'S', 'o',  'n', ' ', 195,  169,  'c', 'o', 'n', 'o',  'm', 'i', 'e',
    ',',  ' ', 'd',  'e', ' ', 't',  'y',  'p', 'e', ' ', 'c',  'a', 'p', 'i',
    't',  'a', 'l',  'i', 's', 't',  'e',  ' ', 'a', 'v', 'e',  'c', ' ', 'u',
    'n',  'e', ' ',  'i', 'n', 't',  'e',  'r', 'v', 'e', 'n',  't', 'i', 'o',
    'n',  ' ', 195,  169, 't', 'a',  't',  'i', 'q', 'u', 'e',  ' ', 'a', 's',
    's',  'e', 'z',  ' ', 'f', 'o',  'r',  't', 'e', ',', ' ',  'f', 'a', 'i',
    't',  ' ', 'd',  226, 128, 153,  'e',  'l', 'l', 'e', ' ',  'u', 'n', ' ',
    'd',  'e', 's',  ' ', 'l', 'e',  'a',  'd', 'e', 'r', 's',  ' ', 'm', 'o',
    'n',  'd', 'i',  'a', 'u', 'x',  ' ',  'd', 'a', 'n', 's',  ' ', 'l', 'e',
    's',  ' ', 's',  'e', 'c', 't',  'e',  'u', 'r', 's', ' ',  'd', 'e', ' ',
    'l',  226, 128,  153, 'a', 'g',  'r',  'o', 'a', 'l', 'i',  'm', 'e', 'n',
    't',  'a', 'i',  'r', 'e', ',',  ' ',  'd', 'e', ' ', 'l',  226, 128, 153,
    'a',  195, 169,  'r', 'o', 'n',  'a',  'u', 't', 'i', 'q',  'u', 'e', ',',
    ' ',  'd', 'e',  ' ', 'l', 226,  128,  153, 'a', 'u', 't',  'o', 'm', 'o',
    'b',  'i', 'l',  'e', ',', ' ',  'd',  'e', 's', ' ', 'p',  'r', 'o', 'd',
    'u',  'i', 't',  's', ' ', 'd',  'e',  ' ', 'l', 'u', 'x',  'e', ',', ' ',
    'd',  'u', ' ',  't', 'o', 'u',  'r',  'i', 's', 'm', 'e',  ' ', 'e', 't',
    ' ',  'd', 'u',  ' ', 'n', 'u',  'c',  'l', 195, 169, 'a',  'i', 'r', 'e',
    '.',  13,  10,   13,  10,  'P',  'e',  'u', 'p', 'l', 195,  169, 'e', ' ',
    'd',  'e', ' ',  '6', '5', ',',  '3',  ' ', 'm', 'i', 'l',  'l', 'i', 'o',
    'n',  's', ' ',  'd', 226, 128,  153,  'h', 'a', 'b', 'i',  't', 'a', 'n',
    't',  's', ' ',  'a', 'u', ' ',  '1',  'e', 'r', ' ', 'j',  'a', 'n', 'v',
    'i',  'e', 'r',  ' ', '2', '0',  '1',  '2', '[', '4', ']',  ',', ' ', 'l',
    'a',  ' ', 'F',  'r', 'a', 'n',  'c',  'e', ' ', 'e', 's',  't', ' ', 'u',
    'n',  ' ', 'p',  'a', 'y', 's',  ' ',  'd', 195, 169, 'v',  'e', 'l', 'o',
    'p',  'p', 195,  169, ',', ' ',  'a',  'v', 'e', 'c', ' ',  'u', 'n', ' ',
    'i',  'n', 'd',  'i', 'c', 'e',  ' ',  'd', 'e', ' ', 'd',  195, 169, 'v',
    'e',  'l', 'o',  'p', 'p', 'e',  'm',  'e', 'n', 't', ' ',  'h', 'u', 'm',
    'a',  'i', 'n',  ' ', 't', 'r',  195,  168, 's', ' ', 195,  169, 'l', 'e',
    'v',  195, 169,  '[', '5', ']',  '.',  13,  10,  13,  10,   'L', 'a', ' ',
    'F',  'r', 'a',  'n', 'c', 'e',  ' ',  'm', 195, 169, 't',  'r', 'o', 'p',
    'o',  'l', 'i',  't', 'a', 'i',  'n',  'e', ' ', 'e', 's',  't', ' ', 's',
    'i',  't', 'u',  195, 169, 'e',  ' ',  195, 160, ' ', 'l',  226, 128, 153,
    'u',  'n', 'e',  ' ', 'd', 'e',  's',  ' ', 'e', 'x', 't',  'r', 195, 169,
    'm',  'i', 't',  195, 169, 's',  ' ',  'o', 'c', 'c', 'i',  'd', 'e', 'n',
    't',  'a', 'l',  'e', 's', ' ',  'd',  'e', ' ', 'l', 226,  128, 153, 'E',
    'u',  'r', 'o',  'p', 'e', '.',  ' ',  'E', 'l', 'l', 'e',  ' ', 'e', 's',
    't',  ' ', 'b',  'o', 'r', 'd',  195,  169, 'e', ' ', 'p',  'a', 'r', ' ',
    'l',  'a', ' ',  'm', 'e', 'r',  ' ',  'd', 'u', ' ', 'N',  'o', 'r', 'd',
    ' ',  'a', 'u',  ' ', 'n', 'o',  'r',  'd', ',', ' ', 'l',  'a', ' ', 'M',
    'a',  'n', 'c',  'h', 'e', ' ',  'a',  'u', ' ', 'n', 'o',  'r', 'd', '-',
    'o',  'u', 'e',  's', 't', ',',  ' ',  'l', 226, 128, 153,  'o', 'c', 195,
    169,  'a', 'n',  ' ', 'A', 't',  'l',  'a', 'n', 't', 'i',  'q', 'u', 'e',
    ' ',  195, 160,  ' ', 'l', 226,  128,  153, 'o', 'u', 'e',  's', 't', ' ',
    'e',  't', ' ',  'l', 'a', ' ',  'm',  'e', 'r', ' ', 'M',  195, 169, 'd',
    'i',  't', 'e',  'r', 'r', 'a',  'n',  195, 169, 'e', ' ',  'a', 'u', ' ',
    's',  'u', 'd',  '-', 'e', 's',  't',  '.', ' ', 'E', 'l',  'l', 'e', ' ',
    'e',  's', 't',  ' ', 'f', 'r',  'o',  'n', 't', 'a', 'l',  'i', 195, 168,
    'r',  'e', ' ',  'd', 'e', ' ',  'l',  'a', ' ', 'B', 'e',  'l', 'g', 'i',
    'q',  'u', 'e',  ' ', 'e', 't',  ' ',  'd', 'u', ' ', 'L',  'u', 'x', 'e',
    'm',  'b', 'o',  'u', 'r', 'g',  ' ',  'a', 'u', ' ', 'n',  'o', 'r', 'd',
    '-',  'e', 's',  't', ',', ' ',  'd',  'e', ' ', 'l', 226,  128, 153, 'A',
    'l',  'l', 'e',  'm', 'a', 'g',  'n',  'e', ' ', 'e', 't',  ' ', 'd', 'e',
    ' ',  'l', 'a',  ' ', 'S', 'u',  'i',  's', 's', 'e', ' ',  195, 160, ' ',
    'l',  226, 128,  153, 'e', 's',  't',  ',', ' ', 'd', 'e',  ' ', 'l', 226,
    128,  153, 'I',  't', 'a', 'l',  'i',  'e', ' ', 'e', 't',  ' ', 'd', 'e',
    ' ',  'M', 'o',  'n', 'a', 'c',  'o',  ' ', 'a', 'u', ' ',  's', 'u', 'd',
    '-',  'e', 's',  't', ',', ' ',  'd',  'e', ' ', 'l', 226,  128, 153, 'E',
    's',  'p', 'a',  'g', 'n', 'e',  ' ',  'e', 't', ' ', 'd',  226, 128, 153,
    'A',  'n', 'd',  'o', 'r', 'r',  'e',  ' ', 'a', 'u', ' ',  's', 'u', 'd',
    '-',  'o', 'u',  'e', 's', 't',  '.',  ' ', 'S', 'i', ' ',  'l', 'e', 's',
    ' ',  'f', 'r',  'o', 'n', 't',  'i',  195, 168, 'r', 'e',  's', ' ', 'd',
    'u',  ' ', 's',  'u', 'd', ' ',  'd',  'u', ' ', 'p', 'a',  'y', 's', ' ',
    'c',  'o', 'r',  'r', 'e', 's',  'p',  'o', 'n', 'd', 'e',  'n', 't', ' ',
    195,  160, ' ',  'd', 'e', 's',  ' ',  'm', 'a', 's', 's',  'i', 'f', 's',
    ' ',  'm', 'o',  'n', 't', 'a',  'g',  'n', 'e', 'u', 'x',  ',', ' ', 'l',
    'e',  's', ' ',  'f', 'r', 'o',  'n',  't', 'i', 195, 168,  'r', 'e', 's',
    ' ',  'd', 'u',  ' ', 'n', 'o',  'r',  'd', '-', 'e', 's',  't', ' ', 'n',
    'e',  ' ', 'c',  'o', 'r', 'r',  'e',  's', 'p', 'o', 'n',  'd', 'e', 'n',
    't',  ' ', 195,  160, ' ', 'a',  'u',  'c', 'u', 'n', 'e',  ' ', 'l', 'i',
    'm',  'i', 't',  'e', ' ', 'g',  195,  169, 'o', 'g', 'r',  'a', 'p', 'h',
    'i',  'q', 'u',  'e', '[', 'n',  'o',  't', 'e', ' ', '6',  ']', ' ', 'n',
    'i',  ' ', 'l',  'i', 'n', 'g',  'u',  'i', 's', 't', 'i',  'q', 'u', 'e',
    '[',  'n', 'o',  't', 'e', ' ',  '7',  ']', '.', ' ', 'L',  'a', ' ', 'F',
    'r',  'a', 'n',  'c', 'e', ' ',  'm',  195, 169, 't', 'r',  'o', 'p', 'o',
    'l',  'i', 't',  'a', 'i', 'n',  'e',  ' ', 'c', 'o', 'm',  'p', 'r', 'e',
    'n',  'd', ' ',  'p', 'l', 'u',  's',  'i', 'e', 'u', 'r',  's', ' ', 195,
    174,  'l', 'e',  's', ',', ' ',  'n',  'o', 't', 'a', 'm',  'm', 'e', 'n',
    't',  ' ', 'l',  'a', ' ', 'C',  'o',  'r', 's', 'e', ' ',  'e', 't', ' ',
    'd',  'e', 's',  ' ', 195, 174,  'l',  'e', 's', ' ', 'c',  195, 180, 't',
    'i',  195, 168,  'r', 'e', 's',  '.',  ' ', 'L', 'a', ' ',  'm', 195, 169,
    't',  'r', 'o',  'p', 'o', 'l',  'e',  ' ', 'e', 's', 't',  ' ', 'c', 'o',
    'm',  'p', 'r',  'i', 's', 'e',  ' ',  'e', 'n', 't', 'r',  'e', ' ', 'l',
    'e',  's', ' ',  'l', 'a', 't',  'i',  't', 'u', 'd', 'e',  's', ' ', '4',
    '2',  194, 176,  '1', '9', '\'', '4',  '6', '"', ' ', 'N',  ' ', 'e', 't',
    ' ',  '5', '1',  194, 176, '5',  '\'', '4', '7', '"', ' ',  'N', ',', ' ',
    'a',  'i', 'n',  's', 'i', ' ',  'q',  'u', 'e', ' ', 'l',  'e', 's', ' ',
    'l',  'o', 'n',  'g', 'i', 't',  'u',  'd', 'e', 's', ' ',  '4', 194, 176,
    '4',  '6', '\'', ' ', 'O', ' ',  'e',  't', ' ', '8', 194,  176, '1', '4',
    '\'', '4', '2',  '"', ' ', 'E',  '.',  13,  10,  13,  10,   'L', 'a', ' ',
    'F',  'r', 'a',  'n', 'c', 'e',  ' ',  'c', 'o', 'm', 'p',  'r', 'e', 'n',
    'd',  ' ', 195,  169, 'g', 'a',  'l',  'e', 'm', 'e', 'n',  't', ' ', 'd',
    'e',  ' ', 'n',  'o', 'm', 'b',  'r',  'e', 'u', 'x', ' ',  't', 'e', 'r',
    'r',  'i', 't',  'o', 'i', 'r',  'e',  's', ' ', 's', 'i',  't', 'u', 195,
    169,  's', ' ',  'e', 'n', '-',  'd',  'e', 'h', 'o', 'r',  's', ' ', 'd',
    'u',  ' ', 'c',  'o', 'n', 't',  'i',  'n', 'e', 'n', 't',  ' ', 'e', 'u',
    'r',  'o', 'p',  195, 169, 'e',  'n',  ',', ' ', 'c', 'o',  'u', 'r', 'a',
    'm',  'm', 'e',  'n', 't', ' ',  'a',  'p', 'p', 'e', 'l',  195, 169, 's',
    ' ',  't', 'e',  'r', 'r', 'i',  't',  'o', 'i', 'r', 'e',  's', ' ', 'd',
    226,  128, 153,  'o', 'u', 't',  'r',  'e', '-', 'm', 'e',  'r', ',', ' ',
    'n',  'a', 'g',  'u', 195, 168,  'r',  'e', ' ', 'D', 'O',  'M', '-', 'T',
    'O',  'M', ',',  ' ', 'q', 'u',  'i',  ' ', 'l', 'u', 'i',  ' ', 'p', 'e',
    'r',  'm', 'e',  't', 't', 'e',  'n',  't', ' ', 'd', 226,  128, 153, 195,
    170,  't', 'r',  'e', ' ', 'p',  'r',  195, 169, 's', 'e',  'n', 't', 'e',
    ' ',  'd', 'a',  'n', 's', ' ',  't',  'o', 'u', 's', ' ',  'l', 'e', 's',
    ' ',  'o', 'c',  195, 169, 'a',  'n',  's', '.', ' ', 'C',  'e', 's', ' ',
    't',  'e', 'r',  'r', 'i', 't',  'o',  'i', 'r', 'e', 's',  ' ', 'a', 'u',
    'x',  ' ', 's',  't', 'a', 't',  'u',  't', 's', ' ', 'v',  'a', 'r', 'i',
    195,  169, 's',  ' ', 's', 'o',  'n',  't', '[', '6', ']',  ' ', ':', 13,
    10,   13,  10,   's', 'u', 'r',  ' ',  'l', 'e', ' ', 'c',  'o', 'n', 't',
    'i',  'n', 'e',  'n', 't', ' ',  's',  'u', 'd', '-', 'a',  'm', 195, 169,
    'r',  'i', 'c',  'a', 'i', 'n',  ' ',  ':', ' ', 'l', 'a',  ' ', 'G', 'u',
    'y',  'a', 'n',  'e', ' ', ';',  13,   10,  'd', 'a', 'n',  's', ' ', 'l',
    226,  128, 153,  'o', 'c', 195,  169,  'a', 'n', ' ', 'A',  't', 'l', 'a',
    'n',  't', 'i',  'q', 'u', 'e',  ' ',  '(', 'A', 'n', 't',  'i', 'l', 'l',
    'e',  's', ')',  ' ', ':', ' ',  'l',  'a', ' ', 'G', 'u',  'a', 'd', 'e',
    'l',  'o', 'u',  'p', 'e', ',',  ' ',  'l', 'a', ' ', 'M',  'a', 'r', 't',
    'i',  'n', 'i',  'q', 'u', 'e',  ',',  ' ', 'S', 'a', 'i',  'n', 't', '-',
    'P',  'i', 'e',  'r', 'r', 'e',  '-',  'e', 't', '-', 'M',  'i', 'q', 'u',
    'e',  'l', 'o',  'n', ',', ' ',  'S',  'a', 'i', 'n', 't',  '-', 'M', 'a',
    'r',  't', 'i',  'n', ' ', 'e',  't',  ' ', 'S', 'a', 'i',  'n', 't', '-',
    'B',  'a', 'r',  't', 'h', 195,  169,  'l', 'e', 'm', 'y',  ' ', ';', 13,
    10,   'd', 'a',  'n', 's', ' ',  'l',  226, 128, 153, 'o',  'c', 195, 169,
    'a',  'n', ' ',  'P', 'a', 'c',  'i',  'f', 'i', 'q', 'u',  'e', ' ', ':',
    ' ',  'l', 'a',  ' ', 'P', 'o',  'l',  'y', 'n', 195, 169,  's', 'i', 'e',
    ' ',  'f', 'r',  'a', 'n', 195,  167,  'a', 'i', 's', 'e',  ',', ' ', 'l',
    'a',  ' ', 'N',  'o', 'u', 'v',  'e',  'l', 'l', 'e', '-',  'C', 'a', 'l',
    195,  169, 'd',  'o', 'n', 'i',  'e',  ',', ' ', 'W', 'a',  'l', 'l', 'i',
    's',  '-', 'e',  't', '-', 'F',  'u',  't', 'u', 'n', 'a',  ' ', 'e', 't',
    ' ',  'C', 'l',  'i', 'p', 'p',  'e',  'r', 't', 'o', 'n',  ' ', ';', 13,
    10,   'd', 'a',  'n', 's', ' ',  'l',  226, 128, 153, 'o',  'c', 195, 169,
    'a',  'n', ' ',  'I', 'n', 'd',  'i',  'e', 'n', ' ', ':',  ' ', 'L', 'a',
    ' ',  'R', 195,  169, 'u', 'n',  'i',  'o', 'n', ',', ' ',  'M', 'a', 'y',
    'o',  't', 't',  'e', ',', ' ',  'l',  'e', 's', ' ', 195,  142, 'l', 'e',
    's',  ' ', 195,  137, 'p', 'a',  'r',  's', 'e', 's', ',',  ' ', 'l', 'e',
    's',  ' ', 195,  142, 'l', 'e',  's',  ' ', 'C', 'r', 'o',  'z', 'e', 't',
    ',',  ' ', 'l',  'e', 's', ' ',  195,  142, 'l', 'e', 's',  ' ', 'K', 'e',
    'r',  'g', 'u',  'e', 'l', 'e',  'n',  ' ', 'e', 't', ' ',  'S', 'a', 'i',
    'n',  't', '-',  'P', 'a', 'u',  'l',  '-', 'e', 't', '-',  'A', 'm', 's',
    't',  'e', 'r',  'd', 'a', 'm',  ' ',  ';', 13,  10,  'e',  'n', ' ', 'A',
    'n',  't', 'a',  'r', 'c', 't',  'i',  'q', 'u', 'e', ' ',  ':', ' ', 'l',
    'a',  ' ', 'T',  'e', 'r', 'r',  'e',  ' ', 'A', 'd', 195,  169, 'l', 'i',
    'e',  '[', 'n',  'o', 't', 'e',  ' ',  '8', ']', '.', 13,   10,  195, 128,
    ' ',  't', 'r',  'a', 'v', 'e',  'r',  's', ' ', 's', 'e',  's', ' ', 'c',
    'o',  'l', 'l',  'e', 'c', 't',  'i',  'v', 'i', 't', 195,  169, 's', ' ',
    'u',  'l', 't',  'r', 'a', '-',  'm',  'a', 'r', 'i', 'n',  'e', 's', ',',
    ' ',  'l', 'a',  ' ', 'F', 'r',  'a',  'n', 'c', 'e', ' ',  'p', 'o', 's',
    's',  195, 168,  'd', 'e', ' ',  195,  169, 'g', 'a', 'l',  'e', 'm', 'e',
    'n',  't', ' ',  'd', 'e', 's',  ' ',  'f', 'r', 'o', 'n',  't', 'i', 195,
    168,  'r', 'e',  's', ' ', 't',  'e',  'r', 'r', 'e', 's',  't', 'r', 'e',
    's',  ' ', 'a',  'v', 'e', 'c',  ' ',  'l', 'e', ' ', 'B',  'r', 195, 169,
    's',  'i', 'l',  ' ', 'e', 't',  ' ',  'l', 'e', ' ', 'S',  'u', 'r', 'i',
    'n',  'a', 'm',  'e', ',', ' ',  'a',  'i', 'n', 's', 'i',  ' ', 'q', 'u',
    226,  128, 153,  'a', 'v', 'e',  'c',  ' ', 'l', 'e', 's',  ' ', 'P', 'a',
    'y',  's', '-',  'B', 'a', 's',  ' ',  'v', 'i', 'a', ' ',  'l', 'a', ' ',
    'p',  'a', 'r',  't', 'i', 'e',  ' ',  'f', 'r', 'a', 'n',  195, 167, 'a',
    'i',  's', 'e',  ' ', 'd', 'e',  ' ',  'S', 'a', 'i', 'n',  't', '-', 'M',
    'a',  'r', 't',  'i', 'n', '.',  13,   10,  13,  10,  'L',  'a', ' ', 's',
    'u',  'p', 'e',  'r', 'f', 'i',  'c',  'i', 'e', ' ', 'd',  'e', ' ', 'l',
    'a',  ' ', 'F',  'r', 'a', 'n',  'c',  'e', ' ', 'e', 's',  't', ' ', 'd',
    'e',  ' ', '6',  '7', '0', ' ',  '9',  '2', '2', ' ', 'k',  'm', 194, 178,
    ',',  ' ', 'o',  'u', ' ', '5',  '4',  '7', ' ', '0', '3',  '0', ' ', 's',
    'a',  'n', 's',  ' ', 'c', 'o',  'm',  'p', 't', 'a', 'b',  'i', 'l', 'i',
    's',  'e', 'r',  ' ', 'l', 226,  128,  153, 'o', 'u', 't',  'r', 'e', '-',
    'm',  'e', 'r',  '[', '7', ']',  '.',  ' ', 'E', 'l', 'l',  'e', ' ', 'e',
    's',  't', ' ',  'l', 'e', ' ',  '4',  '1', 'e', ' ', 'p',  'l', 'u', 's',
    ' ',  'g', 'r',  'a', 'n', 'd',  ' ',  195, 137, 't', 'a',  't', ' ', 'd',
    'u',  ' ', 'm',  'o', 'n', 'd',  'e',  ' ', 'p', 'a', 'r',  ' ', 's', 'a',
    ' ',  's', 'u',  'r', 'f', 'a',  'c',  'e', ' ', 't', 'e',  'r', 'r', 'e',
    's',  't', 'r',  'e', '[', '7',  ']',  ' ', 'e', 't', ' ',  'l', 'e', ' ',
    'd',  'e', 'u',  'x', 'i', 195,  168,  'm', 'e', ' ', 'p',  'a', 'r', ' ',
    's',  'a', ' ',  'z', 'o', 'n',  'e',  ' ', 195, 169, 'c',  'o', 'n', 'o',
    'm',  'i', 'q',  'u', 'e', ' ',  'e',  'x', 'c', 'l', 'u',  's', 'i', 'v',
    'e',  '[', '8',  ']', '.', ' ',  'E',  'l', 'l', 'e', ' ',  'e', 's', 't',
    ' ',  'e', 'n',  ' ', 'o', 'u',  't',  'r', 'e', ' ', 'l',  'e', ' ', 't',
    'r',  'o', 'i',  's', 'i', 195,  168,  'm', 'e', ' ', 'p',  'l', 'u', 's',
    ' ',  'g', 'r',  'a', 'n', 'd',  ' ',  'p', 'a', 'y', 's',  ' ', 'd', 226,
    128,  153, 'E',  'u', 'r', 'o',  'p',  'e', ',', ' ', 'a',  'p', 'r', 195,
    168,  's', ' ',  'l', 'a', ' ',  'R',  'u', 's', 's', 'i',  'e', ' ', 'e',
    't',  ' ', 'l',  226, 128, 153,  'U',  'k', 'r', 'a', 'i',  'n', 'e', ',',
    ' ',  'd', 'e',  'u', 'x', 'i',  195,  168, 'm', 'e', ' ',  's', 'i', ' ',
    'o',  'n', ' ',  'i', 'n', 'c',  'l',  'u', 't', ' ', 'l',  'e', 's', ' ',
    'd',  195, 169,  'p', 'a', 'r',  't',  'e', 'm', 'e', 'n',  't', 's', ' ',
    'u',  'l', 't',  'r', 'a', '-',  'm',  'a', 'r', 'i', 'n',  's', ',', ' ',
    'e',  't', ' ',  'l', 'e', ' ',  'p',  'l', 'u', 's', ' ',  'g', 'r', 'a',
    'n',  'd', ' ',  'd', 'e', ' ',  'l',  226, 128, 153, 'U',  'n', 'i', 'o',
    'n',  ' ', 'e',  'u', 'r', 'o',  'p',  195, 169, 'e', 'n',  'n', 'e', '[',
    '7',  ']', '.',  ' ', 'S', 'o',  'n',  ' ', 't', 'e', 'r',  'r', 'i', 't',
    'o',  'i', 'r',  'e', ' ', 'm',  195,  169, 't', 'r', 'o',  'p', 'o', 'l',
    'i',  't', 'a',  'i', 'n', ' ',  'c',  'o', 'n', 't', 'i',  'n', 'e', 'n',
    't',  'a', 'l',  ' ', 's', 226,  128,  153, 195, 169, 't',  'e', 'n', 'd',
    ' ',  's', 'u',  'r', ' ', 'e',  'n',  'v', 'i', 'r', 'o',  'n', ' ', '1',
    ' ',  '0', '0',  '0', ' ', 'k',  'm',  ' ', 'd', 'u', ' ',  'n', 'o', 'r',
    'd',  ' ', 'a',  'u', ' ', 's',  'u',  'd', ' ', 'e', 't',  ' ', 'd', 226,
    128,  153, 'e',  's', 't', ' ',  'e',  'n', ' ', 'o', 'u',  'e', 's', 't',
    '.',  ' ', 'L',  226, 128, 153,  195,  169, 't', 'e', 'n',  'd', 'u', 'e',
    ' ',  'd', 'e',  ' ', 's', 'o',  'n',  ' ', 'l', 'i', 't',  't', 'o', 'r',
    'a',  'l', ',',  ' ', 'o', 'u',  't',  'r', 'e', '-', 'm',  'e', 'r', ' ',
    'i',  'n', 'c',  'l', 'u', 's',  ',',  ' ', 'e', 's', 't',  ' ', 'd', 'e',
    ' ',  '8', ' ',  '2', '4', '5',  ' ',  'k', 'm', '[', '9',  ']', '.', 13,
    10,   13,  10,   'G', 'r', 'e',  'e',  'k', ':', 13,  10,   13,  10,  206,
    151,  ' ', 206,  149, 206, 187,  206,  187, 206, 172, 206,  180, 206, 177,
    ' ',  '(', 207,  128, 206, 177,  206,  187, 206, 177, 206,  185, 207, 140,
    207,  132, 206,  181, 207, 129,  206,  177, ':', ' ', 225,  188, 153, 206,
    187,  206, 187,  206, 172, 207,  130,  ',', ' ', 206, 181,  207, 128, 206,
    175,  207, 131,  206, 183, 206,  188,  206, 177, ':', ' ',  206, 149, 206,
    187,  206, 187,  206, 183, 206,  189,  206, 185, 206, 186,  206, 174, ' ',
    206,  148, 206,  183, 206, 188,  206,  191, 206, 186, 207,  129, 206, 177,
    207,  132, 206,  175, 206, 177,  ')',  ' ', 206, 181, 206,  175, 206, 189,
    206,  177, 206,  185, ' ', 207,  135,  207, 142, 207, 129,  206, 177, ' ',
    207,  128, 206,  191, 207, 133,  ' ',  206, 178, 207, 129,  206, 175, 207,
    131,  206, 186,  206, 181, 207,  132,  206, 177, 206, 185,  ' ', 207, 131,
    207,  132, 206,  183, ' ', 206,  189,  206, 191, 207, 132,  206, 185, 206,
    191,  206, 177,  206, 189, 206,  177,  207, 132, 206, 191,  206, 187, 206,
    185,  206, 186,  206, 174, ' ',  206,  149, 207, 133, 207,  129, 207, 142,
    207,  128, 206,  183, ',', ' ',  207,  131, 207, 132, 206,  191, ' ', 206,
    189,  206, 191,  207, 132, 206,  185,  207, 140, 207, 132,  206, 181, 207,
    129,  206, 191,  ' ', 206, 172,  206,  186, 207, 129, 206,  191, ' ', 207,
    132,  206, 183,  207, 130, ' ',  206,  146, 206, 177, 206,  187, 206, 186,
    206,  177, 206,  189, 206, 185,  206,  186, 206, 174, 207,  130, ' ', 207,
    135,  206, 181,  207, 129, 207,  131,  206, 191, 206, 189,  206, 174, 207,
    131,  206, 191,  207, 133, ',',  ' ',  207, 131, 207, 132,  206, 183, 206,
    189,  ' ', 206,  145, 206, 189,  206,  177, 207, 132, 206,  191, 206, 187,
    206,  185, 206,  186, 206, 174,  ' ',  206, 156, 206, 181,  207, 131, 207,
    140,  206, 179,  206, 181, 206,  185,  206, 191, '.', 206,  160, 207, 129,
    207,  137, 207,  132, 206, 181,  207,  141, 206, 191, 207,  133, 207, 131,
    206,  177, ' ',  207, 132, 206,  183,  207, 130, ' ', 206,  149, 206, 187,
    206,  187, 206,  172, 206, 180,  206,  191, 207, 130, ' ',  206, 186, 206,
    177,  206, 185,  ' ', 206, 188,  206,  181, 206, 179, 206,  177, 206, 187,
    207,  141, 207,  132, 206, 181,  207,  129, 206, 183, ' ',  207, 128, 207,
    140,  206, 187,  206, 183, ' ',  206,  181, 206, 175, 206,  189, 206, 177,
    206,  185, ' ',  206, 183, ' ',  206,  145, 206, 184, 206,  174, 206, 189,
    206,  177, '.',  13,  10,  13,   10,   206, 163, 207, 133,  206, 189, 206,
    191,  207, 129,  206, 181, 207,  141,  206, 181, 206, 185,  ' ', 207, 131,
    207,  132, 206,  177, ' ', 206,  178,  206, 191, 207, 129,  206, 181, 206,
    185,  206, 191,  206, 180, 207,  133,  207, 132, 206, 185,  206, 186, 206,
    172,  ' ', 206,  188, 206, 181,  ' ',  207, 132, 206, 183,  206, 189, ' ',
    206,  145, 206,  187, 206, 178,  206,  177, 206, 189, 206,  175, 206, 177,
    ',',  ' ', 207,  131, 207, 132,  206,  177, ' ', 206, 178,  207, 140, 207,
    129,  206, 181,  206, 185, 206,  177,  ' ', 206, 188, 206,  181, ' ', 207,
    132,  206, 183,  ' ', 206, 146,  206,  191, 207, 133, 206,  187, 206, 179,
    206,  177, 207,  129, 206, 175,  206,  177, ' ', 206, 186,  206, 177, 206,
    185,  ' ', 207,  132, 206, 183,  206,  189, ' ', 207, 128,  207, 129, 207,
    142,  206, 183,  206, 189, ' ',  206,  147, 206, 185, 206,  191, 207, 133,
    206,  179, 206,  186, 206, 191,  207,  131, 206, 187, 206,  177, 206, 178,
    206,  185, 206,  186, 206, 174,  ' ',  206, 148, 206, 183,  206, 188, 206,
    191,  206, 186,  207, 129, 206,  177,  207, 132, 206, 175,  206, 177, ' ',
    207,  132, 206,  183, 207, 130,  ' ',  206, 156, 206, 177,  206, 186, 206,
    181,  206, 180,  206, 191, 206,  189,  206, 175, 206, 177,  207, 130, ' ',
    '(',  207, 128,  '.', 206, 147,  '.',  206, 148, '.', 206,  156, '.', ')',
    ' ',  206, 186,  206, 177, 206,  185,  ' ', 207, 131, 207,  132, 206, 177,
    ' ',  206, 178,  206, 191, 207,  129,  206, 181, 206, 185,  206, 191, 206,
    177,  206, 189,  206, 177, 207,  132,  206, 191, 206, 187,  206, 185, 206,
    186,  206, 172,  ' ', 206, 188,  206,  181, ' ', 207, 132,  206, 183, 206,
    189,  ' ', 206,  164, 206, 191,  207,  133, 207, 129, 206,  186, 206, 175,
    206,  177, '.',  ' ', 206, 146,  207,  129, 206, 173, 207,  135, 206, 181,
    207,  132, 206,  177, 206, 185,  ' ',  207, 131, 207, 132,  206, 177, ' ',
    206,  177, 206,  189, 206, 177,  207,  132, 206, 191, 206,  187, 206, 185,
    206,  186, 206,  172, ' ', 206,  177,  207, 128, 207, 140,  ' ', 207, 132,
    206,  191, ' ',  206, 145, 206,  185,  206, 179, 206, 177,  206, 175, 206,
    191,  ' ', 206,  160, 206, 173,  206,  187, 206, 177, 206,  179, 206, 191,
    207,  130, ',',  ' ', 207, 131,  207,  132, 206, 177, ' ',  206, 180, 207,
    133,  207, 132,  206, 185, 206,  186,  206, 172, ' ', 206,  177, 207, 128,
    207,  140, ' ',  207, 132, 206,  191,  ' ', 206, 153, 207,  140, 206, 189,
    206,  185, 206,  191, ' ', 206,  186,  206, 177, 206, 185,  ' ', 206, 189,
    207,  140, 207,  132, 206, 185,  206,  177, ' ', 206, 177,  207, 128, 207,
    140,  ' ', 207,  132, 206, 183,  ' ',  206, 156, 206, 181,  207, 131, 207,
    140,  206, 179,  206, 181, 206,  185,  206, 191, ' ', 206,  152, 206, 172,
    206,  187, 206,  177, 207, 131,  207,  131, 206, 177, '.',  206, 151, ' ',
    206,  149, 206,  187, 206, 187,  206,  172, 206, 180, 206,  177, ' ', 206,
    186,  206, 177,  207, 132, 206,  173,  207, 135, 206, 181,  206, 185, ' ',
    207,  132, 206,  183, 206, 189,  ' ',  '1', '1', 206, 183,  ' ', 206, 184,
    206,  173, 207,  131, 206, 183,  ' ',  207, 131, 207, 132,  206, 185, 207,
    130,  ' ', 207,  135, 207, 142,  207,  129, 206, 181, 207,  130, ' ', 206,
    188,  206, 181,  ' ', 207, 132,  206,  183, ' ', 206, 188,  206, 181, 206,
    179,  206, 177,  206, 187, 207,  141,  207, 132, 206, 181,  207, 129, 206,
    183,  ' ', 206,  177, 206, 186,  207,  132, 206, 191, 206,  179, 207, 129,
    206,  177, 206,  188, 206, 188,  206,  174, ' ', 207, 131,  207, 132, 206,
    177,  ' ', '1',  '3', '.', '6',  '7',  '6', ' ', 207, 135,  206, 185, 206,
    187,  206, 185,  207, 140, 206,  188,  206, 181, 207, 132,  207, 129, 206,
    177,  ' ', 206,  186, 206, 177,  206,  184, 207, 142, 207,  130, ' ', 206,
    181,  207, 135,  206, 181, 206,  185,  ' ', 207, 128, 206,  191, 206, 187,
    206,  187, 206,  172, ' ', 206,  189,  206, 183, 207, 131,  206, 185, 206,
    172,  ' ', '(',  207, 128, 206,  181,  207, 129, 206, 175,  207, 128, 206,
    191,  207, 133,  ' ', '1', '.',  '4',  '0', '0', ',', ' ',  206, 181, 206,
    186,  207, 132,  207, 137, 206,  189,  ' ', 206, 191, 207,  128, 206, 191,
    206,  175, 207,  137, 206, 189,  ' ',  207, 132, 206, 177,  ' ', '2', '2',
    '7',  ' ', 206,  186, 206, 177,  207,  132, 206, 191, 206,  185, 206, 186,
    206,  191, 207,  133, 206, 189,  207,  132, 206, 177, 206,  185, ')', ',',
    ' ',  207, 131,  207, 133, 206,  188,  207, 128, 206, 181,  207, 129, 206,
    185,  206, 187,  206, 177, 206,  188,  206, 178, 206, 177,  206, 189, 206,
    191,  206, 188,  206, 173, 206,  189,  207, 137, 206, 189,  ' ', 207, 132,
    206,  183, 207,  130, ' ', 206,  154,  207, 129, 206, 183,  207, 132, 206,
    183,  207, 130,  ',', ' ', 207,  132,  207, 137, 206, 189,  ' ', 206, 148,
    207,  137, 206,  180, 206, 181,  206,  186, 206, 177, 206,  189, 206, 174,
    207,  131, 207,  137, 206, 189,  ',',  ' ', 207, 132, 207,  137, 206, 189,
    ' ',  206, 154,  207, 133, 206,  186,  206, 187, 206, 172,  206, 180, 207,
    137,  206, 189,  ',', ' ', 207,  132,  207, 137, 206, 189,  ' ', 206, 149,
    207,  128, 207,  132, 206, 177,  206,  189, 206, 174, 207,  131, 207, 137,
    206,  189, ' ',  206, 186, 206,  177,  206, 185, ' ', 207,  128, 206, 191,
    206,  187, 206,  187, 207, 142,  206,  189, ' ', 206, 172,  206, 187, 206,
    187,  207, 137,  206, 189, '.',  206,  164, 206, 191, ' ',  207, 136, 206,
    183,  206, 187,  207, 140, 207,  132,  206, 181, 207, 129,  206, 191, ' ',
    206,  178, 206,  191, 207, 133,  206,  189, 207, 140, ' ',  206, 181, 206,
    175,  206, 189,  206, 177, 206,  185,  ' ', 206, 191, ' ',  206, 140, 206,
    187,  207, 133,  206, 188, 207,  128,  206, 191, 207, 130,  ' ', 206, 186,
    206,  177, 206,  185, ' ', 207,  132,  206, 191, ' ', 206,  188, 206, 181,
    206,  179, 206,  177, 206, 187,  207,  141, 207, 132, 206,  181, 207, 129,
    206,  191, ' ',  207, 128, 206,  191,  207, 132, 206, 172,  206, 188, 206,
    185,  ' ', 206,  191, ' ', 206,  145,  206, 187, 206, 185,  206, 172, 206,
    186,  206, 188,  206, 191, 206,  189,  206, 177, 207, 130,  '.', 13,  10,
    13,   10,  206,  136, 207, 135,  206,  181, 206, 185, ' ',  206, 188, 206,
    177,  206, 186,  207, 129, 206,  172,  ' ', 206, 186, 206,  177, 206, 185,
    ' ',  207, 128,  206, 187, 206,  191,  207, 141, 207, 131,  206, 185, 206,
    177,  ' ', 206,  185, 207, 131,  207,  132, 206, 191, 207,  129, 206, 175,
    206,  177, ' ',  206, 186, 206,  177,  207, 132, 206, 172,  ' ', 207, 132,
    206,  183, 206,  189, ' ', 206,  191,  207, 128, 206, 191,  206, 175, 206,
    177,  ' ', 206,  172, 207, 131,  206,  186, 206, 183, 207,  131, 206, 181,
    ' ',  206, 188,  206, 181, 206,  179,  206, 172, 206, 187,  206, 183, ' ',
    207,  128, 206,  191, 206, 187,  206,  185, 207, 132, 206,  185, 207, 131,
    206,  188, 206,  185, 206, 186,  206,  174, ' ', 206, 181,  207, 128, 206,
    175,  206, 180,  207, 129, 206,  177,  207, 131, 206, 183,  ' ', 207, 131,
    206,  181, ' ',  207, 132, 207,  129,  206, 181, 206, 185,  207, 130, ' ',
    206,  183, 207,  128, 206, 181,  206,  175, 207, 129, 206,  191, 207, 133,
    207,  130, '.',  206, 149, 206,  180,  207, 142, ' ', 206,  179, 206, 181,
    206,  189, 206,  189, 206, 174,  206,  184, 206, 183, 206,  186, 206, 181,
    ' ',  206, 183,  ' ', 206, 180,  206,  183, 206, 188, 206,  191, 206, 186,
    207,  129, 206,  177, 207, 132,  206,  175, 206, 177, ' ',  206, 186, 206,
    177,  206, 185,  ' ', 206, 183,  ' ',  207, 134, 206, 185,  206, 187, 206,
    191,  207, 131,  206, 191, 207,  134,  206, 175, 206, 177,  '.', 206, 145,
    206,  186, 207,  140, 206, 188,  206,  188, 206, 177, ' ',  206, 183, ' ',
    206,  149, 206,  187, 206, 187,  206,  172, 206, 180, 206,  177, ' ', 206,
    181,  206, 175,  206, 189, 206,  177,  206, 185, ' ', 206,  191, ' ', 207,
    132,  207, 140,  207, 128, 206,  191,  207, 130, ' ', 206,  179, 206, 173,
    206,  189, 206,  189, 206, 183,  207,  131, 206, 183, 207,  130, ' ', 207,
    132,  207, 137,  206, 189, ' ',  206,  159, 206, 187, 207,  133, 206, 188,
    207,  128, 206,  185, 206, 177,  206,  186, 207, 142, 206,  189, ' ', 206,
    145,  206, 179,  207, 142, 206,  189,  207, 137, 206, 189,  ',', 207, 132,
    206,  191, 207,  133, ' ', 206,  180,  207, 129, 206, 172,  206, 188, 206,
    177,  207, 132,  206, 191, 207,  130,  ',', ' ', 207, 132,  206, 183, 207,
    130,  ' ', 207,  132, 207, 129,  206,  177, 206, 179, 207,  137, 206, 180,
    206,  175, 206,  177, 207, 130,  ' ',  206, 186, 206, 177,  206, 185, ' ',
    207,  132, 206,  183, 207, 130,  ' ',  206, 186, 207, 137,  206, 188, 206,
    188,  207, 137,  206, 180, 206,  175,  206, 177, 207, 130,  ' ', '.', 13,
    10,   13,  10,   206, 151, ' ',  206,  149, 206, 187, 206,  187, 206, 172,
    206,  180, 206,  177, ' ', 206,  181,  206, 175, 206, 189,  206, 177, 206,
    185,  ' ', 206,  188, 206, 173,  206,  187, 206, 191, 207,  130, ' ', 207,
    132,  207, 137,  206, 189, ' ',  206,  149, 207, 133, 207,  129, 207, 137,
    207,  128, 206,  177, 207, 138,  206,  186, 207, 142, 206,  189, ' ', 206,
    154,  206, 191,  206, 185, 206,  189,  206, 191, 207, 132,  206, 174, 207,
    132,  207, 137,  206, 189, '/',  206,  149, 207, 133, 207,  129, 207, 137,
    207,  128, 206,  177, 207, 138,  206,  186, 206, 174, 207,  130, ' ', 206,
    136,  206, 189,  207, 137, 207,  131,  206, 183, 207, 130,  ' ', 206, 177,
    207,  128, 207,  140, ' ', 207,  132,  206, 191, ' ', '1',  '9', '8', '1',
    ',',  ' ', 207,  132, 206, 183,  207,  130, ' ', 206, 149,  207, 133, 207,
    129,  207, 137,  206, 182, 207,  142,  206, 189, 206, 183,  207, 130, ' ',
    206,  177, 207,  128, 207, 140,  ' ',  207, 132, 206, 191,  ' ', '2', '0',
    '0',  '1', ',',  ' ', 207, 132,  206,  191, 207, 133, ' ',  206, 157, 206,
    145,  206, 164,  206, 159, ' ',  206,  177, 207, 128, 207,  140, ' ', 207,
    132,  206, 191,  ' ', '1', '9',  '5',  '2', ' ', 206, 186,  206, 177, 206,
    185,  ' ', 206,  185, 206, 180,  207,  129, 207, 133, 207,  132, 206, 185,
    206,  186, 207,  140, ' ', 206,  188,  206, 173, 206, 187,  206, 191, 207,
    130,  ' ', 207,  132, 206, 191,  207,  133, ' ', 206, 159,  206, 151, 206,
    149,  ' ', '(',  '1', '9', '4',  '5',  ')', '.', ' ', 206,  151, ' ', 206,
    149,  206, 187,  206, 187, 206,  172,  206, 180, 206, 177,  ' ', 206, 181,
    206,  175, 206,  189, 206, 177,  206,  185, ' ', 206, 188,  206, 185, 206,
    177,  ' ', 206,  177, 206, 189,  206,  181, 207, 128, 207,  132, 207, 133,
    206,  179, 206,  188, 206, 173,  206,  189, 206, 183, ' ',  207, 135, 207,
    142,  207, 129,  206, 177, ' ',  206,  188, 206, 181, ' ',  207, 133, 207,
    136,  206, 183,  206, 187, 207,  140,  ' ', 206, 186, 206,  177, 207, 132,
    206,  172, ' ',  206, 186, 206,  181,  207, 134, 206, 177,  206, 187, 206,
    174,  206, 189,  ' ', 206, 181,  206,  185, 207, 131, 207,  140, 206, 180,
    206,  183, 206,  188, 206, 177,  ' ',  206, 186, 206, 177,  206, 185, ' ',
    207,  128, 206,  191, 206, 187,  207,  141, ' ', 207, 133,  207, 136, 206,
    183,  206, 187,  207, 140, ' ',  206,  180, 206, 181, 206,  175, 206, 186,
    207,  132, 206,  183, ' ', 206,  177,  206, 189, 206, 184,  207, 129, 207,
    142,  207, 128,  206, 185, 206,  189,  206, 183, 207, 130,  ' ', 206, 177,
    206,  189, 206,  172, 207, 128,  207,  132, 207, 133, 206,  190, 206, 183,
    207,  130, '.',  ' ', 206, 154,  206,  177, 207, 132, 206,  173, 207, 135,
    206,  181, 206,  185, ' ', 207,  132,  206, 183, 206, 189,  ' ', '2', '2',
    206,  183, ' ',  206, 186, 206,  177,  206, 187, 207, 141,  207, 132, 206,
    181,  207, 129,  206, 183, ' ',  207,  128, 206, 191, 206,  185, 207, 140,
    207,  132, 206,  183, 207, 132,  206,  177, ' ', 206, 182,  207, 137, 206,
    174,  207, 130,  ' ', 207, 131,  207,  132, 206, 191, 206,  189, ' ', 206,
    186,  207, 140,  207, 131, 206,  188,  206, 191, '.', '[',  '4', ']', 13,
    10,   13,  10,   206, 151, ' ',  206,  149, 206, 187, 206,  187, 206, 172,
    206,  180, 206,  177, ' ', '(',  207,  128, 206, 177, 206,  187, 206, 177,
    206,  185, 207,  140, 207, 132,  206,  181, 207, 129, 206,  177, ':', ' ',
    225,  188, 153,  206, 187, 206,  187,  206, 172, 207, 130,  ',', ' ', 206,
    181,  207, 128,  206, 175, 207,  131,  206, 183, 206, 188,  206, 177, ':',
    ' ',  206, 149,  206, 187, 206,  187,  206, 183, 206, 189,  206, 185, 206,
    186,  206, 174,  ' ', 206, 148,  206,  183, 206, 188, 206,  191, 206, 186,
    207,  129, 206,  177, 207, 132,  206,  175, 206, 177, ')',  ' ', 206, 181,
    206,  175, 206,  189, 206, 177,  206,  185, ' ', 207, 135,  207, 142, 207,
    129,  206, 177,  ' ', 207, 128,  206,  191, 207, 133, ' ',  206, 178, 207,
    129,  206, 175,  207, 131, 206,  186,  206, 181, 207, 132,  206, 177, 206,
    185,  ' ', 207,  131, 207, 132,  206,  183, ' ', 206, 189,  206, 191, 207,
    132,  206, 185,  206, 191, 206,  177,  206, 189, 206, 177,  207, 132, 206,
    191,  206, 187,  206, 185, 206,  186,  206, 174, ' ', 206,  149, 207, 133,
    207,  129, 207,  142, 207, 128,  206,  183, ',', ' ', 207,  131, 207, 132,
    206,  191, ' ',  206, 189, 206,  191,  207, 132, 206, 185,  207, 140, 207,
    132,  206, 181,  207, 129, 206,  191,  ' ', 206, 172, 206,  186, 207, 129,
    206,  191, ' ',  207, 132, 206,  183,  207, 130, ' ', 206,  146, 206, 177,
    206,  187, 206,  186, 206, 177,  206,  189, 206, 185, 206,  186, 206, 174,
    207,  130, ' ',  207, 135, 206,  181,  207, 129, 207, 131,  206, 191, 206,
    189,  206, 174,  207, 131, 206,  191,  207, 133, ',', ' ',  207, 131, 207,
    132,  206, 183,  206, 189, ' ',  206,  145, 206, 189, 206,  177, 207, 132,
    206,  191, 206,  187, 206, 185,  206,  186, 206, 174, ' ',  206, 156, 206,
    181,  207, 131,  207, 140, 206,  179,  206, 181, 206, 185,  206, 191, '.',
    206,  160, 207,  129, 207, 137,  207,  132, 206, 181, 207,  141, 206, 191,
    207,  133, 207,  131, 206, 177,  ' ',  207, 132, 206, 183,  207, 130, ' ',
    206,  149, 206,  187, 206, 187,  206,  172, 206, 180, 206,  191, 207, 130,
    ' ',  206, 186,  206, 177, 206,  185,  ' ', 206, 188, 206,  181, 206, 179,
    206,  177, 206,  187, 207, 141,  207,  132, 206, 181, 207,  129, 206, 183,
    ' ',  207, 128,  207, 140, 206,  187,  206, 183, ' ', 206,  181, 206, 175,
    206,  189, 206,  177, 206, 185,  ' ',  206, 183, ' ', 206,  145, 206, 184,
    206,  174, 206,  189, 206, 177,  '.',  13,  10,  13,  10,   206, 163, 207,
    133,  206, 189,  206, 191, 207,  129,  206, 181, 207, 141,  206, 181, 206,
    185,  ' ', 207,  131, 207, 132,  206,  177, ' ', 206, 178,  206, 191, 207,
    129,  206, 181,  206, 185, 206,  191,  206, 180, 207, 133,  207, 132, 206,
    185,  206, 186,  206, 172, ' ',  206,  188, 206, 181, ' ',  207, 132, 206,
    183,  206, 189,  ' ', 206, 145,  206,  187, 206, 178, 206,  177, 206, 189,
    206,  175, 206,  177, ',', ' ',  207,  131, 207, 132, 206,  177, ' ', 206,
    178,  207, 140,  207, 129, 206,  181,  206, 185, 206, 177,  ' ', 206, 188,
    206,  181, ' ',  207, 132, 206,  183,  ' ', 206, 146, 206,  191, 207, 133,
    206,  187, 206,  179, 206, 177,  207,  129, 206, 175, 206,  177, ' ', 206,
    186,  206, 177,  206, 185, ' ',  207,  132, 206, 183, 206,  189, ' ', 207,
    128,  207, 129,  207, 142, 206,  183,  206, 189, ' ', 206,  147, 206, 185,
    206,  191, 207,  133, 206, 179,  206,  186, 206, 191, 207,  131, 206, 187,
    206,  177, 206,  178, 206, 185,  206,  186, 206, 174, ' ',  206, 148, 206,
    183,  206, 188,  206, 191, 206,  186,  207, 129, 206, 177,  207, 132, 206,
    175,  206, 177,  ' ', 207, 132,  206,  183, 207, 130, ' ',  206, 156, 206,
    177,  206, 186,  206, 181, 206,  180,  206, 191, 206, 189,  206, 175, 206,
    177,  207, 130,  ' ', '(', 207,  128,  '.', 206, 147, '.',  206, 148, '.',
    206,  156, '.',  ')', ' ', 206,  186,  206, 177, 206, 185,  ' ', 207, 131,
    207,  132, 206,  177, ' ', 206,  178,  206, 191, 207, 129,  206, 181, 206,
    185,  206, 191,  206, 177, 206,  189,  206, 177, 207, 132,  206, 191, 206,
    187,  206, 185,  206, 186, 206,  172,  ' ', 206, 188, 206,  181, ' ', 207,
    132,  206, 183,  206, 189, ' ',  206,  164, 206, 191, 207,  133, 207, 129,
    206,  186, 206,  175, 206, 177,  '.',  ' ', 206, 146, 207,  129, 206, 173,
    207,  135, 206,  181, 207, 132,  206,  177, 206, 185, ' ',  207, 131, 207,
    132,  206, 177,  ' ', 206, 177,  206,  189, 206, 177, 207,  132, 206, 191,
    206,  187, 206,  185, 206, 186,  206,  172, ' ', 206, 177,  207, 128, 207,
    140,  ' ', 207,  132, 206, 191,  ' ',  206, 145, 206, 185,  206, 179, 206,
    177,  206, 175,  206, 191, ' ',  206,  160, 206, 173, 206,  187, 206, 177,
    206,  179, 206,  191, 207, 130,  ',',  ' ', 207, 131, 207,  132, 206, 177,
    ' ',  206, 180,  207, 133, 207,  132,  206, 185, 206, 186,  206, 172, ' ',
    206,  177, 207,  128, 207, 140,  ' ',  207, 132, 206, 191,  ' ', 206, 153,
    207,  140, 206,  189, 206, 185,  206,  191, ' ', 206, 186,  206, 177, 206,
    185,  ' ', 206,  189, 207, 140,  207,  132, 206, 185, 206,  177, ' ', 206,
    177,  207, 128,  207, 140, ' ',  207,  132, 206, 183, ' ',  206, 156, 206,
    181,  207, 131,  207, 140, 206,  179,  206, 181, 206, 185,  206, 191, ' ',
    206,  152, 206,  172, 206, 187,  206,  177, 207, 131, 207,  131, 206, 177,
    '.',  206, 151,  ' ', 206, 149,  206,  187, 206, 187, 206,  172, 206, 180,
    206,  177, ' ',  206, 186, 206,  177,  207, 132, 206, 173,  207, 135, 206,
    181,  206, 185,  ' ', 207, 132,  206,  183, 206, 189, ' ',  '1', '1', 206,
    183,  ' ', 206,  184, 206, 173,  207,  131, 206, 183, ' ',  207, 131, 207,
    132,  206, 185,  207, 130, ' ',  207,  135, 207, 142, 207,  129, 206, 181,
    207,  130, ' ',  206, 188, 206,  181,  ' ', 207, 132, 206,  183, ' ', 206,
    188,  206, 181,  206, 179, 206,  177,  206, 187, 207, 141,  207, 132, 206,
    181,  207, 129,  206, 183, ' ',  206,  177, 206, 186, 207,  132, 206, 191,
    206,  179, 207,  129, 206, 177,  206,  188, 206, 188, 206,  174, ' ', 207,
    131,  207, 132,  206, 177, ' ',  '1',  '3', '.', '6', '7',  '6', ' ', 207,
    135,  206, 185,  206, 187, 206,  185,  207, 140, 206, 188,  206, 181, 207,
    132,  207, 129,  206, 177, ' ',  206,  186, 206, 177, 206,  184, 207, 142,
    207,  130, ' ',  206, 181, 207,  135,  206, 181, 206, 185,  ' ', 207, 128,
    206,  191, 206,  187, 206, 187,  206,  172, ' ', 206, 189,  206, 183, 207,
    131,  206, 185,  206, 172, ' ',  '(',  207, 128, 206, 181,  207, 129, 206,
    175,  207, 128,  206, 191, 207,  133,  ' ', '1', '.', '4',  '0', '0', ',',
    ' ',  206, 181,  206, 186, 207,  132,  207, 137, 206, 189,  ' ', 206, 191,
    207,  128, 206,  191, 206, 175,  207,  137, 206, 189, ' ',  207, 132, 206,
    177,  ' ', '2',  '2', '7', ' ',  206,  186, 206, 177, 207,  132, 206, 191,
    206,  185, 206,  186, 206, 191,  207,  133, 206, 189, 207,  132, 206, 177,
    206,  185, ')',  ',', ' ', 207,  131,  207, 133, 206, 188,  207, 128, 206,
    181,  207, 129,  206, 185, 206,  187,  206, 177, 206, 188,  206, 178, 206,
    177,  206, 189,  206, 191, 206,  188,  206, 173, 206, 189,  207, 137, 206,
    189,  ' ', 207,  132, 206, 183,  207,  130, ' ', 206, 154,  207, 129, 206,
    183,  207, 132,  206, 183, 207,  130,  ',', ' ', 207, 132,  207, 137, 206,
    189,  ' ', 206,  148, 207, 137,  206,  180, 206, 181, 206,  186, 206, 177,
    206,  189, 206,  174, 207, 131,  207,  137, 206, 189, ',',  ' ', 207, 132,
    207,  137, 206,  189, ' ', 206,  154,  207, 133, 206, 186,  206, 187, 206,
    172,  206, 180,  207, 137, 206,  189,  ',', ' ', 207, 132,  207, 137, 206,
    189,  ' ', 206,  149, 207, 128,  207,  132, 206, 177, 206,  189, 206, 174,
    207,  131, 207,  137, 206, 189,  ' ',  206, 186, 206, 177,  206, 185, ' ',
    207,  128, 206,  191, 206, 187,  206,  187, 207, 142, 206,  189, ' ', 206,
    172,  206, 187,  206, 187, 207,  137,  206, 189, '.', 206,  164, 206, 191,
    ' ',  207, 136,  206, 183, 206,  187,  207, 140, 207, 132,  206, 181, 207,
    129,  206, 191,  ' ', 206, 178,  206,  191, 207, 133, 206,  189, 207, 140,
    ' ',  206, 181,  206, 175, 206,  189,  206, 177, 206, 185,  ' ', 206, 191,
    ' ',  206, 140,  206, 187, 207,  133,  206, 188, 207, 128,  206, 191, 207,
    130,  ' ', 206,  186, 206, 177,  206,  185, ' ', 207, 132,  206, 191, ' ',
    206,  188, 206,  181, 206, 179,  206,  177, 206, 187, 207,  141, 207, 132,
    206,  181, 207,  129, 206, 191,  ' ',  207, 128, 206, 191,  207, 132, 206,
    172,  206, 188,  206, 185, ' ',  206,  191, ' ', 206, 145,  206, 187, 206,
    185,  206, 172,  206, 186, 206,  188,  206, 191, 206, 189,  206, 177, 207,
    130,  '.', 13,   10,  13,  10,   206,  136, 207, 135, 206,  181, 206, 185,
    ' ',  206, 188,  206, 177, 206,  186,  207, 129, 206, 172,  ' ', 206, 186,
    206,  177, 206,  185, ' ', 207,  128,  206, 187, 206, 191,  207, 141, 207,
    131,  206, 185,  206, 177, ' ',  206,  185, 207, 131, 207,  132, 206, 191,
    207,  129, 206,  175, 206, 177,  ' ',  206, 186, 206, 177,  207, 132, 206,
    172,  ' ', 207,  132, 206, 183,  206,  189, ' ', 206, 191,  207, 128, 206,
    191,  206, 175,  206, 177, ' ',  206,  172, 207, 131, 206,  186, 206, 183,
    207,  131, 206,  181, ' ', 206,  188,  206, 181, 206, 179,  206, 172, 206,
    187,  206, 183,  ' ', 207, 128,  206,  191, 206, 187, 206,  185, 207, 132,
    206,  185, 207,  131, 206, 188,  206,  185, 206, 186, 206,  174, ' ', 206,
    181,  207, 128,  206, 175, 206,  180,  207, 129, 206, 177,  207, 131, 206,
    183,  ' ', 207,  131, 206, 181,  ' ',  207, 132, 207, 129,  206, 181, 206,
    185,  207, 130,  ' ', 206, 183,  207,  128, 206, 181, 206,  175, 207, 129,
    206,  191, 207,  133, 207, 130,  '.',  206, 149, 206, 180,  207, 142, ' ',
    206,  179, 206,  181, 206, 189,  206,  189, 206, 174, 206,  184, 206, 183,
    206,  186, 206,  181, ' ', 206,  183,  ' ', 206, 180, 206,  183, 206, 188,
    206,  191, 206,  186, 207, 129,  206,  177, 207, 132, 206,  175, 206, 177,
    ' ',  206, 186,  206, 177, 206,  185,  ' ', 206, 183, ' ',  207, 134, 206,
    185,  206, 187,  206, 191, 207,  131,  206, 191, 207, 134,  206, 175, 206,
    177,  '.', 206,  145, 206, 186,  207,  140, 206, 188, 206,  188, 206, 177,
    ' ',  206, 183,  ' ', 206, 149,  206,  187, 206, 187, 206,  172, 206, 180,
    206,  177, ' ',  206, 181, 206,  175,  206, 189, 206, 177,  206, 185, ' ',
    206,  191, ' ',  207, 132, 207,  140,  207, 128, 206, 191,  207, 130, ' ',
    206,  179, 206,  173, 206, 189,  206,  189, 206, 183, 207,  131, 206, 183,
    207,  130, ' ',  207, 132, 207,  137,  206, 189, ' ', 206,  159, 206, 187,
    207,  133, 206,  188, 207, 128,  206,  185, 206, 177, 206,  186, 207, 142,
    206,  189, ' ',  206, 145, 206,  179,  207, 142, 206, 189,  207, 137, 206,
    189,  ',', 207,  132, 206, 191,  207,  133, ' ', 206, 180,  207, 129, 206,
    172,  206, 188,  206, 177, 207,  132,  206, 191, 207, 130,  ',', ' ', 207,
    132,  206, 183,  207, 130, ' ',  207,  132, 207, 129, 206,  177, 206, 179,
    207,  137, 206,  180, 206, 175,  206,  177, 207, 130, ' ',  206, 186, 206,
    177,  206, 185,  ' ', 207, 132,  206,  183, 207, 130, ' ',  206, 186, 207,
    137,  206, 188,  206, 188, 207,  137,  206, 180, 206, 175,  206, 177, 207,
    130,  ' ', '.',  13,  10,  13,   10,   206, 151, ' ', 206,  149, 206, 187,
    206,  187, 206,  172, 206, 180,  206,  177, ' ', 206, 181,  206, 175, 206,
    189,  206, 177,  206, 185, ' ',  206,  188, 206, 173, 206,  187, 206, 191,
    207,  130, ' ',  207, 132, 207,  137,  206, 189, ' ', 206,  149, 207, 133,
    207,  129, 207,  137, 207, 128,  206,  177, 207, 138, 206,  186, 207, 142,
    206,  189, ' ',  206, 154, 206,  191,  206, 185, 206, 189,  206, 191, 207,
    132,  206, 174,  207, 132, 207,  137,  206, 189, '/', 206,  149, 207, 133,
    207,  129, 207,  137, 207, 128,  206,  177, 207, 138, 206,  186, 206, 174,
    207,  130, ' ',  206, 136, 206,  189,  207, 137, 207, 131,  206, 183, 207,
    130,  ' ', 206,  177, 207, 128,  207,  140, ' ', 207, 132,  206, 191, ' ',
    '1',  '9', '8',  '1', ',', ' ',  207,  132, 206, 183, 207,  130, ' ', 206,
    149,  207, 133,  207, 129, 207,  137,  206, 182, 207, 142,  206, 189, 206,
    183,  207, 130,  ' ', 206, 177,  207,  128, 207, 140, ' ',  207, 132, 206,
    191,  ' ', '2',  '0', '0', '1',  ',',  ' ', 207, 132, 206,  191, 207, 133,
    ' ',  206, 157,  206, 145, 206,  164,  206, 159, ' ', 206,  177, 207, 128,
    207,  140, ' ',  207, 132, 206,  191,  ' ', '1', '9', '5',  '2', ' ', 206,
    186,  206, 177,  206, 185, ' ',  206,  185, 206, 180, 207,  129, 207, 133,
    207,  132, 206,  185, 206, 186,  207,  140, ' ', 206, 188,  206, 173, 206,
    187,  206, 191,  207, 130, ' ',  207,  132, 206, 191, 207,  133, ' ', 206,
    159,  206, 151,  206, 149, ' ',  '(',  '1', '9', '4', '5',  ')', '.', ' ',
    206,  151, ' ',  206, 149, 206,  187,  206, 187, 206, 172,  206, 180, 206,
    177,  ' ', 206,  181, 206, 175,  206,  189, 206, 177, 206,  185, ' ', 206,
    188,  206, 185,  206, 177, ' ',  206,  177, 206, 189, 206,  181, 207, 128,
    207,  132, 207,  133, 206, 179,  206,  188, 206, 173, 206,  189, 206, 183,
    ' ',  207, 135,  207, 142, 207,  129,  206, 177, ' ', 206,  188, 206, 181,
    ' ',  207, 133,  207, 136, 206,  183,  206, 187, 207, 140,  ' ', 206, 186,
    206,  177, 207,  132, 206, 172,  ' ',  206, 186, 206, 181,  207, 134, 206,
    177,  206, 187,  206, 174, 206,  189,  ' ', 206, 181, 206,  185, 207, 131,
    207,  140, 206,  180, 206, 183,  206,  188, 206, 177, ' ',  206, 186, 206,
    177,  206, 185,  ' ', 207, 128,  206,  191, 206, 187, 207,  141, ' ', 207,
    133,  207, 136,  206, 183, 206,  187,  207, 140, ' ', 206,  180, 206, 181,
    206,  175, 206,  186, 207, 132,  206,  183, ' ', 206, 177,  206, 189, 206,
    184,  207, 129,  207, 142, 207,  128,  206, 185, 206, 189,  206, 183, 207,
    130,  ' ', 206,  177, 206, 189,  206,  172, 207, 128, 207,  132, 207, 133,
    206,  190, 206,  183, 207, 130,  '.',  ' ', 206, 154, 206,  177, 207, 132,
    206,  173, 207,  135, 206, 181,  206,  185, ' ', 207, 132,  206, 183, 206,
    189,  ' ', '2',  '2', 206, 183,  ' ',  206, 186, 206, 177,  206, 187, 207,
    141,  207, 132,  206, 181, 207,  129,  206, 183, ' ', 207,  128, 206, 191,
    206,  185, 207,  140, 207, 132,  206,  183, 207, 132, 206,  177, ' ', 206,
    182,  207, 137,  206, 174, 207,  130,  ' ', 207, 131, 207,  132, 206, 191,
    206,  189, ' ',  206, 186, 207,  140,  207, 131, 206, 188,  206, 191, '.',
    '[',  '4', ']',  13,  10,  13,   10,   'R', 'a', 'n', 'd',  'o', 'm', ' ',
    'Q',  'u', 'a',  'd', ' ', 'V',  'a',  'l', 'u', 'e', 's',  13,  10,  240,
    144,  128, 128,  240, 152, 166,  171,  240, 158, 187, 174,  240, 154, 170,
    170,  240, 154,  132, 163, 240,  155,  132, 163, 243, 187,  174, 187, 244,
    128,  128, 128,  243, 174, 187,  174,  242, 187, 174, 187,  13,  10,  0
};

static
const char * const charUtf8MultiLang = (const char *) utf8MultiLang;

enum { NUM_UTF8_MULTI_LANG_CODE_POINTS = 11781 };

static
bsl::string dumpStr(const bsl::string& str)
    // Returns the specified 'str' in a human-readable hex format.
{
    bsl::string ret;

    const char *begin = str.c_str();
    const char *end   = &*str.end();

    for (const char *pc = begin; pc < end; ++pc) {
        if (begin != pc) {
            ret.push_back(' ');
        }

        for (int shiftDown = 4; shiftDown >= 0; shiftDown -= 4) {
            int digit = (*pc >> shiftDown) & 0xf;
            ret.push_back(digit < 10 ? char('0' + digit)
                                     : char('a' + digit - 10));
        }
    }

    return ret;
}

static inline
int intAbs(int x)
    // Return roughly the absolute value of the specified 'x'.
{
    x = x < 0 ? -x : x;
    return x < 0 ? ~x : x;
}

static inline
unsigned int randUnsigned()
    // Return a pseudo-random unsigned integer.
{
    static bsls::Types::Uint64 randAccum = 0;

    randAccum = randAccum * 6364136223846793005LL + 1442695040888963407LL;
    return unsigned(randAccum >> 32);
}

static
void appendRand1Byte(bsl::string *dst)
    // Append a random 1-byte UTF-8 character to the specified '*dst'.
{
    enum {
        k_LOW_BOUND  =    1,
        k_HIGH_BOUND = 0x7f,
        k_MOD_BY     = k_HIGH_BOUND + 1 - k_LOW_BOUND };

    unsigned val = randUnsigned() % k_MOD_BY + k_LOW_BOUND;

    BSLS_ASSERT(val <= k_HIGH_BOUND);

    unsigned char buf[2];
    buf[0] = static_cast<unsigned char>(val);
    buf[1] = 0;

    *dst += reinterpret_cast<const char *>(&buf[0]);
}

static
void appendRand2Byte(bsl::string *dst)
    // Append a random 2-byte UTF-8 character to the specified '*dst'.
{
    enum {
        k_LOW_BOUND  =  0x80,
        k_HIGH_BOUND = 0x7ff,
        k_MOD_BY     = k_HIGH_BOUND + 1 - k_LOW_BOUND };

    unsigned val = randUnsigned() % k_MOD_BY + k_LOW_BOUND;

    BSLS_ASSERT(val <= k_HIGH_BOUND);

    unsigned char buf[3];
    buf[0] = static_cast<unsigned char>(((val & 0x7c0) >> 6) | 0xc0);
    buf[1] = static_cast<unsigned char> ((val &  0x3f)       | 0x80);
    buf[2] = 0;

    *dst += reinterpret_cast<const char *>(&buf[0]);
}

static
void appendRand3Byte(bsl::string *dst)
    // Append a random 3-byte UTF-8 character to the specified '*dst'.
{
    enum {
        k_LOW_BOUND  =  0x800,
        k_HIGH_BOUND = 0xffff,
        k_MOD_BY     = k_HIGH_BOUND + 1 - k_LOW_BOUND };

    unsigned val;
    do {
        val = randUnsigned() % k_MOD_BY + k_LOW_BOUND;
    } while (val >= 0xd800 && val <= 0xdfff);

    BSLS_ASSERT(val <= k_HIGH_BOUND);

    unsigned char buf[4];
    buf[0] = static_cast<unsigned char>(((val & 0xf000) >> 12) | 0xe0);
    buf[1] = static_cast<unsigned char>(((val &  0xfc0) >>  6) | 0x80);
    buf[2] = static_cast<unsigned char> ((val &   0x3f)        | 0x80);
    buf[3] = 0;

    *dst += reinterpret_cast<const char *>(&buf[0]);
}

static
void appendRand4Byte(bsl::string *dst)
    // Append a random 4-byte UTF-8 character to the specified '*dst'.
{
    enum {
        k_LOW_BOUND  =  0x10000,
        k_HIGH_BOUND = 0x10ffff,
        k_MOD_BY     = k_HIGH_BOUND + 1 - k_LOW_BOUND };

    unsigned val = randUnsigned() % k_MOD_BY + k_LOW_BOUND;

    BSLS_ASSERT(val <= k_HIGH_BOUND);

    unsigned char buf[5];
    buf[0] = static_cast<unsigned char>(((val & 0x1c0000) >> 18) | 0xf0);
    buf[1] = static_cast<unsigned char>(((val &  0x3f000) >> 12) | 0x80);
    buf[2] = static_cast<unsigned char>(((val &    0xfc0) >>  6) | 0x80);
    buf[3] = static_cast<unsigned char> ((val &     0x3f)        | 0x80);
    buf[4] = 0;

    *dst += reinterpret_cast<const char *>(&buf[0]);
}

static
void appendRandCorrectCodePoint(bsl::string *dst,
                                bool         useZero,
                                int          numBytes = -1)
    // Append a random valid UTF-8 character to the specified '*dst'.  The '\0'
    // byte is only possible if the specified 'useZero' is 'true'.  Optionally
    // specify 'numBytes'.  If '0 == numBytes' append a '\0', otherwise
    // 'numBytes' is the length in bytes of the random sequence to be appended.
    // If 'numBytes' is not specified, a random value in the range '[ 1 .. 4 ]'
    // will be used.  The behavior is undefined if a value of 'numBytes'
    // outside the range '[ 1 .. 4 ]' is specified.
{
    unsigned r;
    if (-1 == numBytes) {
        r = randUnsigned();
        r = useZero ? r % 5
                    : (r & 3) + 1;
    }
    else {
        BSLS_ASSERT(0 <= numBytes && numBytes <= 4);

        r = useZero && 1 == numBytes && 0 == randUnsigned() % 5 ? 0
                                                                : numBytes;
    }

    switch (r) {
      case 0: {
        dst->push_back('\0');
      } break;
      case 1: {
        appendRand1Byte(dst);
      } break;
      case 2: {
        appendRand2Byte(dst);
      } break;
      case 3: {
        appendRand3Byte(dst);
      } break;
      case 4: {
        appendRand4Byte(dst);
      } break;
      default: {
        ASSERT(0);
      }
    }
}

bsl::string code8(int b)
    // Return the encoded representation of the 7-bit Unicode code point
    // specified by 'b'.  Note that this is simply 'b'.
{
    bsl::string ret;

    ASSERT(0 == (b & ~0x7f));

    ret += char(b);

    return ret;
}

static
bsl::string code16(int b)
    // Return the encoded representation of the 2-byte Unicode code point
    // specified by 'b'.
{
    ASSERT(0 == (b & ~0x7ff));

    unsigned char buf[3];
    buf[0] = static_cast<unsigned char>(((b & 0x7c0) >> 6) | 0xc0);
    buf[1] = static_cast<unsigned char> ((b &  0x3f)       | 0x80);
    buf[2] = 0;

    return reinterpret_cast<char *>(buf);
}

static
bsl::string code24(int b)
    // Return the encoded representation of the 3-byte Unicode code point
    // specified by 'b'.
{
    ASSERT(0 == (b & ~0xffff));

    unsigned char buf[4];
    buf[0] = static_cast<unsigned char>(((b & 0xf000) >> 12) | 0xe0);
    buf[1] = static_cast<unsigned char>(((b &  0xfc0) >>  6) | 0x80);
    buf[2] = static_cast<unsigned char> ((b &   0x3f)        | 0x80);
    buf[3] = 0;

    return reinterpret_cast<char *>(buf);
}

static
bsl::string code32(int b)
    // Return the encoded representation of the 4-byte Unicode code point
    // specified by 'b'.
{
    ASSERT(static_cast<unsigned>(b) <= 0x10ffff);

    unsigned char buf[5];
    buf[0] = static_cast<unsigned char>(((b & 0x1c0000) >> 18) | 0xf0);
    buf[1] = static_cast<unsigned char>(((b &  0x3f000) >> 12) | 0x80);
    buf[2] = static_cast<unsigned char>(((b &    0xfc0) >>  6) | 0x80);
    buf[3] = static_cast<unsigned char> ((b &     0x3f)        | 0x80);
    buf[4] = 0;

    return reinterpret_cast<char *>(buf);
}

static
bsl::string utf8Encode(int b)
    // Return the encoded representation of the specified Unicode code point
    // 'b'.
{
    ASSERT(static_cast<unsigned>(b) <= 0x10ffff);

    if (b <= 0x7f) {
        return code8(b);                                              // RETURN
    }
    if (b <= 0x7ff) {
        return code16(b);                                             // RETURN
    }
    if (b <= 0xffff) {
        return code24(b);                                             // RETURN
    }

    return code32(b);
}

static
bsl::string codeBOM()
    // Return the encoded representation of a UTF-8 Byte Order Mark.
{
    unsigned char buf[4];
    buf[0] = 0xef;
    buf[1] = 0xbb;
    buf[2] = 0xbf;
    buf[3] = 0;

    return reinterpret_cast<char *>(buf);
}

// Note these decoders all assume they can look as far as they want down the
// stream of bytes without provoking a segfault.

static
unsigned int decode8(const char *pc)
    // Return the decoded value of the 1-byte UTF-8 code point pointed to by
    // the specified 'pc'.  Note that this is just '*pc'.
{
    ASSERT(!(~0x7f & *pc));

    return *pc;
}

static
unsigned int decode16(const char *pc)
    // Return the decoded value of the 2-byte UTF-8 code point pointed to by
    // the specified 'pc'.
{
    ASSERT(0xc0 == (*pc & 0xe0) && 0x80 == (pc[1] & 0xc0));

    return ((0x1f & *pc) << 6) | (0x3f & pc[1]);
}

static
unsigned int decode24(const char *pc)
    // Return the decoded value of the 3-byte UTF-8 code point pointed to by
    // the specified 'pc'.
{
    ASSERT(0xe0 == (*pc & 0xf0) && 0x80 == (pc[1] & 0xc0) &&
                                   0x80 == (pc[2] & 0xc0));

    return ((0xf & *pc) << 12) | ((0x3f & pc[1]) << 6) | (0x3f & pc[2]);
}

static
unsigned int decode32(const char *pc)
    // Return the decoded value of the 4-byte UTF-8 code point pointed to by
    // the specified 'pc'.
{
    ASSERT(0xf0 == (*pc & 0xf8) && 0x80 == (pc[1] & 0xc0) &&
                             0x80 == (pc[2] & 0xc0) && 0x80 == (pc[3] & 0xc0));

    return (( 0x7 & *pc)   << 18) | ((0x3f & pc[1]) << 12) |
           ((0x3f & pc[2]) <<  6) |  (0x3f & pc[3]);
}

static
unsigned int decode(const char **pc)
    // Return the decoded value of the UTF-8 code point pointed to by the
    // specified '*pc', updating '*pc' to point to the next code point.
{
    int ret;

    char c = **pc;
    if (0    == (~0x7f & c)) {
        ret = decode8(*pc);
        ++ *pc;
    } else if (0xc0 == (0xe0 & c)) {
        ret = decode16(*pc);
        *pc += 2;
    } else if (0xe0 == (0xf0 & c)) {
        ret = decode24(*pc);
        *pc += 3;
    } else if (0xf0 == (0xf8 & c)) {
        ret = decode32(*pc);
        *pc += 4;
    } else {
        ASSERT(0);

        return -1;                                                    // RETURN
    }

    return ret;
}

static
unsigned int decode(const char *pc)
    // Return the decoded value of the UTF-8 code point pointed to by the
    // specified 'pc'.
{
    return decode(&pc);
}

static
bsls::Types::Uint64 randAccum = 0;

static
int intendedSequenceLength(char firstChar)
    // Return the length of a UTF-8 sequence that begins with the specified
    // 'firstChar', or -1 if 'firstChar' is a continuation character.
{
    switch (static_cast<unsigned char>(firstChar) >> 4) {
      case 0x0:
      case 0x1:
      case 0x2:
      case 0x3:
      case 0x4:
      case 0x5:
      case 0x6:
      case 0x7: {
        return 1;                                                     // RETURN
      } break;
      case 0x8:
      case 0x9:
      case 0xa:
      case 0xb: {
        return -1;                                                    // RETURN
      } break;
      case 0xc:
      case 0xd: {
        return 2;                                                     // RETURN
      } break;
      case 0xe: {
        return 3;                                                     // RETURN
      } break;
      case 0xf: {
        return 4;                                                     // RETURN
      } break;
      default: {
        BSLS_ASSERT(0);

        return -1;                                                    // RETURN
      }
    }
}

int randNum()
    // MMIX Linear Congruential Generator algorithm by Donald Knuth
{
    randAccum = randAccum * 6364136223846793005LL + 1442695040888963407LL;
    return int(randAccum >> 32);
}

static
int randVal()
    // Return a random integer in the '[0..0x1fffff]' range.
{
    return (randNum() >> 9) & 0x1fffff;
}

static
int randVal8(bool never0 = false)
    // Return a random integer in the '[1..0x7f]' range.  If the optionally
    // specified 'never0' is 'true', the range is '[0..0x7f]'.
{
    int ret;
    do {
        ret = randVal() & 0x7f;
    } while (never0 && 0 == ret);

    return ret;
}

static
int randVal16()
    // Return a random integer in the '[0x80..0x7ff]' range.
{
    int ret;
    do {
        ret = randVal() & 0x7ff;
    } while (ret < 0x80);

    return ret;
}

static
int randVal24(bool neverSurrogates = false)
    // Return a random integer in the '[0x800..0xffff]' range.  If the
    // optionally specified 'neverSurrogates' is 'true', do not return values
    // in the '[0xd800..0xdfff]' surrogates range.
{
    int ret;
    do {
        ret = randVal() & 0xffff;
    } while (ret < 0x800 ||
                          (neverSurrogates && ret >= 0xd800 && ret <= 0xdfff));

    return ret;
}

static
int randVal32()
    // Return a random integer in the '[0x10000..0x10ffff]' range.
{
    int ret;
    do {
        ret = (randVal() & 0xfffff) + (randVal() & 0x7ffff);
    } while (ret > 0x10ffff || ret < 0x10000);

    return ret;
}

static
int randValue(bool strict = false, bool never0 = false)
    // Return a random integer in the '[0..0x10ffff]' range.  If the optionally
    // specified 'strict' is 'true', do not return values in the
    // '[0xd800..0xdfff]' surrogates range.  If the optionally specified
    // 'never0' is true, the range is '[1..0x10ffff]'.
{
    int type = randVal();
    switch (type & 3) {
      case 0: {
        return randVal8(never0);                                      // RETURN
      } break;
      case 1: {
        return randVal16();                                           // RETURN
      } break;
      case 2: {
        return randVal24(strict);                                     // RETURN
      } break;
      case 3: {
        return randVal32();                                           // RETURN
      }
    }

    ASSERT(0);
    return 0;
}

static
bool allValid(const bsl::string& str)
    // Return 'true' if all the UTF-8 code points in the specified 'str' are
    // valid and 'false' otherwise.
{
    const bool a = Obj::isValid(str.c_str());
    ASSERT(Obj::isValid(str.data(), str.length()) == a);

    const char *invalid = 0;
    ASSERT(a == (0 <= Obj::numCodePointsIfValid(&invalid,
                                                str.data(),
                                                str.length())));
    ASSERT(a == !invalid);

    invalid = 0;
    ASSERT(a == (0 <= Obj::numCodePointsIfValid(&invalid,
                                                str.c_str())));
    ASSERT(a == !invalid);

    return a;
}

static
IntPtr allNumCodePoints(const bsl::string& str)
    // Return the total number of code points in the specified UTF-8 'str'.
{
    IntPtr len = Obj::numCharacters(str.data(), str.length());
    ASSERT(Obj::numCharacters(str.c_str())                 == len);
    ASSERT(Obj::numCodePointsRaw(str.data(), str.length()) == len);
    ASSERT(Obj::numCodePointsRaw(str.c_str())              == len);

    return len;
}

static
IntPtr allNumCodePointsIfValid(const char         **invalidPointArg,
                               const bsl::string&   str)
    // Run both 'numCodePointsIfValid' overloads on the specified 'str' and
    // check that they yield identical results, and return those results.
    // Return the address of any invalid UTF-8 in the specified
    // 'invalidPointArg'
{
    *invalidPointArg = 0;
    const IntPtr ret = Obj::numCodePointsIfValid(invalidPointArg, str.c_str());

    const char *invalidPointLocal = 0;
    ASSERT(ret == Obj::numCodePointsIfValid(&invalidPointLocal,
                                            str.data(),
                                            str.length()));
    ASSERT(invalidPointLocal == *invalidPointArg);

    invalidPointLocal = 0;
    ASSERT(ret == Obj::numCharactersIfValid(&invalidPointLocal,
                                            str.data(),
                                            str.length()));
    ASSERT(invalidPointLocal == *invalidPointArg);

    invalidPointLocal = 0;
    ASSERT(ret == Obj::numCharactersIfValid(&invalidPointLocal,
                                            str.c_str()));
    ASSERT(invalidPointLocal == *invalidPointArg);

    return ret;
}

static
IntPtr allAdvanceIfValid(int                 *statusArg,
                         const char         **invalidPointArg,
                         const bsl::string&   str)
    // Run both the 4 and 5 argument overloads of 'advanceIfValid' on the
    // specified 'str', check that they yield the same results.  Return the
    // number of code points, and set the specified 'statusArg' to the type of
    // error encountered (or 0 if no error), and set the specified
    // 'invalidPointArg' to the address of the first UTF-8 error.
{
    const IntPtr infinity = bsl::numeric_limits<IntPtr>::max();

    int         statusLocal = 100;
    const char *invalidPointLocal = 0;

    const IntPtr ret = Obj::advanceIfValid(statusArg,
                                           invalidPointArg,
                                           str.c_str(),
                                           infinity);
    ASSERT(ret == Obj::advanceIfValid(&statusLocal,
                                      &invalidPointLocal,
                                      str.data(),
                                      str.length(),
                                      infinity));
    ASSERT(statusLocal       == *statusArg);
    ASSERT(invalidPointLocal == *invalidPointArg);

    return ret;
}

static
bsl::string clone(const char *pc, int length)
    // Return a 'bsl::string' containing the specified 'length' bytes from the
    // specified 'pc'.
{
    bsl::string ret;

    ret.insert(0, pc, length);
    return ret;
}

// Some useful (mostly) multi-octet code points:

    // The 2 lowest non-0 1-octet code points.
    #define U8_00001  "\x01"
    #define U8_00002  "\x02"

    // The 2 highest 1-octet code points.
    #define U8_0007e  "\x7e"
    #define U8_0007f  "\x7f"

    // The 2 lowest 2-octet code points.
    #define U8_00080  "\xc2\x80"
    #define U8_00081  "\xc2\x81"

    // A traditional "interesting" code point, 0xff.
    #define U8_000ff  "\xc3\xbf"

    // The 2 highest 2-octet code points.
    #define U8_007fe  "\xdf\xbe"
    #define U8_007ff  "\xdf\xbf"

    // The 2 lowest 3-octet code points.
    #define U8_00800  "\xe0\xa0\x80"
    #define U8_00801  "\xe0\xa0\x81"

    // The 2 highest 3-octet code points.
    #define U8_0fffe  "\xef\xbf\xbe"
    #define U8_0ffff  "\xef\xbf\xbf"

    // The 2 lowest 4-octet code points.
    #define U8_10000  "\xf0\x90\x80\x80"
    #define U8_10001  "\xf0\x90\x80\x81"

    // The 2 highest 4-octet code points.
    #define U8_10fffe "\xf4\x8f\xbf\xbe"
    #define U8_10ffff "\xf4\x8f\xbf\xbf"

static const struct {
    int           d_lineNum;    // source line number
    const char   *d_utf8_p;     // UTF-8 input string
    unsigned int  d_codePoint;  // 32-bit code point value
} legalCodepointData[] = {
    //L#      UTF-8          code point
    //--      -----          ----------
    { L_,     U8_00001,      decode(U8_00001) },
    { L_,     U8_00002,      decode(U8_00002) },
    { L_,       "\x03",      decode("\x03")   },
    { L_,       "\x04",      decode("\x04")   },
    { L_,       "\x05",      decode("\x05")   },
    { L_,       "\x06",      decode("\x06")   },
    { L_,       "\x07",      decode("\x07")   },
    { L_,       "\x08",      decode("\x08")   },
    { L_,       "\x09",      decode("\x09")   },
    { L_,       "\x0a",      decode("\x0a")   },
    { L_,       "\x0b",      decode("\x0b")   },
    { L_,       "\x0c",      decode("\x0c")   },
    { L_,       "\x0d",      decode("\x0d")   },
    { L_,       "\x0e",      decode("\x0e")   },
    { L_,       "\x0f",      decode("\x0f")   },
    { L_,       "\x10",      decode("\x10")   },
    { L_,       "\x11",      decode("\x11")   },
    { L_,       "\x12",      decode("\x12")   },
    { L_,       "\x13",      decode("\x13")   },
    { L_,       "\x14",      decode("\x14")   },
    { L_,       "\x15",      decode("\x15")   },
    { L_,       "\x16",      decode("\x16")   },
    { L_,       "\x17",      decode("\x17")   },
    { L_,       "\x18",      decode("\x18")   },
    { L_,       "\x19",      decode("\x19")   },
    { L_,       "\x1a",      decode("\x1a")   },
    { L_,       "\x1b",      decode("\x1b")   },
    { L_,       "\x1c",      decode("\x1c")   },
    { L_,       "\x1d",      decode("\x1d")   },
    { L_,       "\x1e",      decode("\x1e")   },
    { L_,       "\x1f",      decode("\x1f")   },
    { L_,       "\x20",      decode("\x20")   },
    { L_,       "\x21",      decode("\x21")   },
    { L_,       "\x22",      decode("\x22")   },
    { L_,       "\x23",      decode("\x23")   },
    { L_,       "\x24",      decode("\x24")   },
    { L_,       "\x25",      decode("\x25")   },
    { L_,       "\x26",      decode("\x26")   },
    { L_,       "\x27",      decode("\x27")   },
    { L_,       "\x28",      decode("\x28")   },
    { L_,       "\x29",      decode("\x29")   },
    { L_,       "\x2a",      decode("\x2a")   },
    { L_,       "\x2b",      decode("\x2b")   },
    { L_,       "\x2c",      decode("\x2c")   },
    { L_,       "\x2d",      decode("\x2d")   },
    { L_,       "\x2e",      decode("\x2e")   },
    { L_,       "\x2f",      decode("\x2f")   },
    { L_,       "\x30",      decode("\x30")   },
    { L_,       "\x31",      decode("\x31")   },
    { L_,       "\x32",      decode("\x32")   },
    { L_,       "\x33",      decode("\x33")   },
    { L_,       "\x34",      decode("\x34")   },
    { L_,       "\x35",      decode("\x35")   },
    { L_,       "\x36",      decode("\x36")   },
    { L_,       "\x37",      decode("\x37")   },
    { L_,       "\x38",      decode("\x38")   },
    { L_,       "\x39",      decode("\x39")   },
    { L_,       "\x3a",      decode("\x3a")   },
    { L_,       "\x3b",      decode("\x3b")   },
    { L_,       "\x3c",      decode("\x3c")   },
    { L_,       "\x3d",      decode("\x3d")   },
    { L_,       "\x3e",      decode("\x3e")   },
    { L_,       "\x3f",      decode("\x3f")   },
    { L_,       "\x40",      decode("\x40")   },
    { L_,       "\x41",      decode("\x41")   },
    { L_,       "\x42",      decode("\x42")   },
    { L_,       "\x43",      decode("\x43")   },
    { L_,       "\x44",      decode("\x44")   },
    { L_,       "\x45",      decode("\x45")   },
    { L_,       "\x46",      decode("\x46")   },
    { L_,       "\x47",      decode("\x47")   },
    { L_,       "\x48",      decode("\x48")   },
    { L_,       "\x49",      decode("\x49")   },
    { L_,       "\x4a",      decode("\x4a")   },
    { L_,       "\x4b",      decode("\x4b")   },
    { L_,       "\x4c",      decode("\x4c")   },
    { L_,       "\x4d",      decode("\x4d")   },
    { L_,       "\x4e",      decode("\x4e")   },
    { L_,       "\x4f",      decode("\x4f")   },
    { L_,       "\x50",      decode("\x50")   },
    { L_,       "\x51",      decode("\x51")   },
    { L_,       "\x52",      decode("\x52")   },
    { L_,       "\x53",      decode("\x53")   },
    { L_,       "\x54",      decode("\x54")   },
    { L_,       "\x55",      decode("\x55")   },
    { L_,       "\x56",      decode("\x56")   },
    { L_,       "\x57",      decode("\x57")   },
    { L_,       "\x58",      decode("\x58")   },
    { L_,       "\x59",      decode("\x59")   },
    { L_,       "\x5a",      decode("\x5a")   },
    { L_,       "\x5b",      decode("\x5b")   },
    { L_,       "\x5c",      decode("\x5c")   },
    { L_,       "\x5d",      decode("\x5d")   },
    { L_,       "\x5e",      decode("\x5e")   },
    { L_,       "\x5f",      decode("\x5f")   },
    { L_,       "\x60",      decode("\x60")   },
    { L_,       "\x61",      decode("\x61")   },
    { L_,       "\x62",      decode("\x62")   },
    { L_,       "\x63",      decode("\x63")   },
    { L_,       "\x64",      decode("\x64")   },
    { L_,       "\x65",      decode("\x65")   },
    { L_,       "\x66",      decode("\x66")   },
    { L_,       "\x67",      decode("\x67")   },
    { L_,       "\x68",      decode("\x68")   },
    { L_,       "\x69",      decode("\x69")   },
    { L_,       "\x6a",      decode("\x6a")   },
    { L_,       "\x6b",      decode("\x6b")   },
    { L_,       "\x6c",      decode("\x6c")   },
    { L_,       "\x6d",      decode("\x6d")   },
    { L_,       "\x6e",      decode("\x6e")   },
    { L_,       "\x6f",      decode("\x6f")   },
    { L_,       "\x70",      decode("\x70")   },
    { L_,       "\x71",      decode("\x71")   },
    { L_,       "\x72",      decode("\x72")   },
    { L_,       "\x73",      decode("\x73")   },
    { L_,       "\x74",      decode("\x74")   },
    { L_,       "\x75",      decode("\x75")   },
    { L_,       "\x76",      decode("\x76")   },
    { L_,       "\x77",      decode("\x77")   },
    { L_,       "\x78",      decode("\x78")   },
    { L_,       "\x79",      decode("\x79")   },
    { L_,       "\x7a",      decode("\x7a")   },
    { L_,       "\x7b",      decode("\x7b")   },
    { L_,       "\x7c",      decode("\x7c")   },
    { L_,       "\x7d",      decode("\x7d")   },
    { L_,     U8_0007e,      decode(U8_0007e) },
    { L_,     U8_0007f,      decode(U8_0007f) },
    { L_,     U8_00080,      decode(U8_00080) },
    { L_,     U8_00081,      decode(U8_00081) },
    { L_,     U8_000ff,      decode(U8_000ff) },
    { L_,     U8_007fe,      decode(U8_007fe) },
    { L_,     U8_007ff,      decode(U8_007ff) },
    { L_,     U8_00800,      decode(U8_00800) },
    { L_,     U8_00801,      decode(U8_00801) },
    { L_,     U8_0fffe,      decode(U8_0fffe) },
    { L_,     U8_0ffff,      decode(U8_0ffff) },
    { L_,     U8_10000,      decode(U8_10000) },
    { L_,     U8_10001,      decode(U8_10001) },
    { L_,     U8_10fffe,     decode(U8_10fffe) },
    { L_,     U8_10ffff,     decode(U8_10ffff) },
};

enum {
    NUM_INTERESTING_CODEPOINTS =
        sizeof legalCodepointData / sizeof *legalCodepointData
};

// ============================================================================
//                               Usage Example 3
// ----------------------------------------------------------------------------

namespace USAGE_3 {

//
///Example 3: Validating UTF-8 Read from a 'bsl::streambuf'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this usage example, we will demonstrate reading and validating UTF-8
// from a stream.
//
// We write a function to read valid UTF-8 to a 'bsl::string'.  We don't know
// how long the input will be, so we don't know how long to make the string
// before we start.  We will grow the string in small, 32-byte increments.
//..
    int utf8StreambufToString(bsl::string    *output,
                              bsl::streambuf *sb)
        // Read valid UTF-8 from the specified streambuf 'sb' to the specified
        // 'output'.  Return 0 if the input was exhausted without encountering
        // any invalid UTF-8, and a non-zero value otherwise.  If invalid UTF-8
        // is encountered, log a message describing the problem after loading
        // all the valid UTF-8 preceding it into 'output'.  Note that after the
        // call, in no case will 'output' contain any invalid UTF-8.
    {
        enum { k_READ_LENGTH = 32 };

        output->clear();
        while (true) {
            bsl::size_t len = output->length();
            output->resize(len + k_READ_LENGTH);
            int status;
            IntPtr numBytes = bdlde::Utf8Util::readIfValid(&status,
                                                           &(*output)[len],
                                                           k_READ_LENGTH,
                                                           sb);
            BSLS_ASSERT(0 <= numBytes);
            BSLS_ASSERT(numBytes <= k_READ_LENGTH);

            output->resize(len + numBytes);
            if (0 < status) {
                // Buffer was full before the end of input was encountered.
                // Note that 'numBytes' may be up to 3 bytes less than
                // 'k_READ_LENGTH'.

                BSLS_ASSERT(k_READ_LENGTH - 4 < numBytes);

                // Go on to grow the string and get more input.

                continue;
            }
            else if (0 == status) {
                // Success!  We've reached the end of input without
                // encountering any invalid UTF-8.

                return 0;                                             // RETURN
            }
            else {
                // Invalid UTF-8 encountered; the value of 'status' indicates
                // the exact nature of the problem.  'numBytes' returned from
                // the above call indicated the number of valid UTF-8 bytes
                // read before encountering the invalid UTF-8.

if (verbose) {
                BSLS_LOG_ERROR("Invalid UTF-8 error %s at position %u.\n",
                               bdlde::Utf8Util::toAscii(status),
                               static_cast<unsigned>(output->length()));
}

                return -1;                                            // RETURN
            }
        }
    }
//..

}  // close namespace USAGE_3

// ============================================================================
//                       HELPER DEFINITIONS FOR TEST 4
// ----------------------------------------------------------------------------

namespace BDLDE_UTF8UTIL_CASE_4 {

const int  surrogates[] = {0xd800,
                          0xd811,
                          0xd9a3,
                          0xd9ff,
                          0xda00,
                          0xda35,
                          0xdb80,
                          0xdbff,
                          0xdc00,
                          0xdc48,
                          0xdd84,
                          0xddff,
                          0xde00,
                          0xde73,
                          0xdf24,
                          0xdfff};
const int *loSgates     = surrogates;
const int *hiSgates     = surrogates + 8;    // beginning of high surrogates

bsl::string codeRandSurrogate()
    // Return a random surrogate.
{
    int val = randNum();
    if (val & 0x1800) {
        val = (val & 0x7ff) + 0xd800;
    }
    else {
        val = surrogates[val & 0xf];
    }

    return code24(val);
}

bsl::string codeRandSurrogatePair()
    // Return a pair of random surrogates.
{
    int val = randNum();
    int loSgate, hiSgate;
    if (val & (3 << 20)) {
        loSgate = 0xd800 + (val & 0x3ff);
        hiSgate = 0xdc00 + ((val >> 10) & 0x3ff);
    }
    else {
        loSgate = loSgates[val & 7];
        hiSgate = hiSgates[(val >> 3) & 7];
    }

    return code24(loSgate) + code24(hiSgate);
}

bsl::string codeRandBenign()
    // Return a random UTF-8 code point with no zeroes or surrogates.
{
    int val;
    do {
        val = randVal();
    } while (0 == val || (0xd800 <= val && 0xdfff >= val) || val > 0x10ffff);

    return utf8Encode(val);
}

}  // close namespace BDLDE_UTF8UTIL_CASE_4

// ============================================================================
//                       HELPER DEFINITIONS FOR TEST 2
// ----------------------------------------------------------------------------

namespace BDLDE_UTF8UTIL_CASE_2 {

bsl::string makeString(const char *pc, size_t len)
    // Return a 'bsl::string' containing the specified 'len' bytes from the
    // specified 'pc'.
{
    bsl::string ret;

    ret.insert(0, pc, len);

    return ret;
}

#define STR(testId)  makeString(encode ## testId, sizeof(encode ## testId))

}  // close namespace BDLDE_UTF8UTIL_CASE_2

const Obj::ErrorStatus EIT = Obj::k_END_OF_INPUT_TRUNCATION;
const Obj::ErrorStatus UCO = Obj::k_UNEXPECTED_CONTINUATION_OCTET;
const Obj::ErrorStatus NCO = Obj::k_NON_CONTINUATION_OCTET;
const Obj::ErrorStatus OLE = Obj::k_OVERLONG_ENCODING;
const Obj::ErrorStatus IIO = Obj::k_INVALID_INITIAL_OCTET;
const Obj::ErrorStatus VTL = Obj::k_VALUE_LARGER_THAN_0X10FFFF;
const Obj::ErrorStatus SUR = Obj::k_SURROGATE;

static const struct {
    int         d_lineNum;    // source line number

    const char *d_utf8_p;     // UTF-8 input string

    int         d_numBytes;   // length of spec (in bytes), not including
                              // null-terminator

    int         d_numCodePoints;
                              // number of UTF-8 code points (-1 if invalid)

    int         d_errOffset;  // byte offset to first invalid sequence;
                              // -1 if valid

    int         d_isValid;    // 1 if valid UTF-8; 0 otherwise
} DATA[] = {
    //L#  input                          #b   #c  eo  result
    //--  -----                          --  ---  --  ------
    { L_, "",                             0,   0, -1,   1   },
    { L_, " ",                            1,   1, -1,   1   },

    { L_, "H",                            1,   1, -1,   1   },
    { L_, "He",                           2,   2, -1,   1   },
    { L_, "Hel",                          3,   3, -1,   1   },
    { L_, "Hell",                         4,   4, -1,   1   },
    { L_, "Hello",                        5,   5, -1,   1   },

    // Check the boundary between 1-octet and 2-octet code points.

    { L_, "\x7f",                         1,   1, -1,   1   },
    { L_, U8_00080,                       2,   1, -1,   1   },

    // Check the boundary between 2-octet and 3-octet code points.

    { L_, U8_007ff,                       2,   1, -1,   1   },
    { L_, U8_00800,                       3,   1, -1,   1   },

    // Check the maximal 3-octet code point.

    { L_, U8_0ffff,                       3,   1, -1,   1   },

    // Make sure 4-octet code points are handled correctly.

    { L_, U8_10000,                       4,   1, -1,   1   },
    { L_, U8_10000 " ",                   5,   2, -1,   1   },
    { L_, " " U8_10001 " ",               6,   3, -1,   1   },
    { L_, U8_10fffe,                      4,   1, -1,   1   },
    { L_, U8_10fffe " ",                  5,   2, -1,   1   },
    { L_, " " U8_10ffff " ",              6,   3, -1,   1   },

    // unexpected continuation octets

    { L_, "\x80",                         1, UCO,  0,   0   },
    { L_, "\x85p",                        2, UCO,  0,   0   },
    { L_, "a\x85",                        2, UCO,  1,   0   },
    { L_, "\x90",                         1, UCO,  0,   0   },
    { L_, " \x91",                        2, UCO,  1,   0   },
    { L_, "\x9a",                         1, UCO,  0,   0   },
    { L_, " \x9f",                        2, UCO,  1,   0   },
    { L_, " \xa0",                        2, UCO,  1,   0   },
    { L_, "\xa1",                         1, UCO,  0,   0   },
    { L_, "7\xaa",                        2, UCO,  1,   0   },
    { L_, "\xaf",                         1, UCO,  0,   0   },
    { L_, " \xb0",                        2, UCO,  1,   0   },
    { L_, "\xb1",                         1, UCO,  0,   0   },
    { L_, "\xba",                         1, UCO,  0,   0   },
    { L_, "p\xbf",                        2, UCO,  1,   0   },

    // Make sure partial 4-octet code points are handled correctly (with a
    // single error).

    { L_, "\xf0",                         1, EIT,  0,   0   },
    { L_, "\xf0\x80",                     2, EIT,  0,   0   },
    { L_, "\xf0\x80\x80",                 3, EIT,  0,   0   },
    { L_, "\xf0 ",                        2, NCO,  0,   0   },
    { L_, "\xf0\x80 ",                    3, NCO,  0,   0   },
    { L_, "\xf0\x80\x80 ",                4, NCO,  0,   0   },

    // Make sure partial 4-octet code points are handled correctly (with a
    // single error).

    { L_, "\xe0\x80",                     2, EIT,  0,   0   },
    { L_, "\xe0",                         1, EIT,  0,   0   },
    { L_, "\xe0\x80 ",                    3, NCO,  0,   0   },
    { L_, "\xe0 ",                        2, NCO,  0,   0   },

    // Make sure the "illegal" UTF-8 octets are handled correctly:
    //   o The octet values C0, C1, F5 to FF never appear.

    { L_, "\xc0",                         1, EIT,  0,   0   },
    { L_, "\xc1",                         1, EIT,  0,   0   },
    { L_, "\xf0",                         1, EIT,  0,   0   },
    { L_, "\xf5",                         1, EIT,  0,   0   },
    { L_, "\xf6",                         1, EIT,  0,   0   },
    { L_, "\xf7",                         1, EIT,  0,   0   },
    { L_, "\xf8",                         1, IIO,  0,   0   },
    { L_, "\xf8\xaf\xaf\xaf",             4, IIO,  0,   0   },
    { L_, "\xf8\x80\x80\x80",             4, IIO,  0,   0   },
    { L_, "\xf8",                         1, IIO,  0,   0   },
    { L_, "\xf9",                         1, IIO,  0,   0   },
    { L_, "\xfa",                         1, IIO,  0,   0   },
    { L_, "\xfb",                         1, IIO,  0,   0   },
    { L_, "\xfc",                         1, IIO,  0,   0   },
    { L_, "\xfd",                         1, IIO,  0,   0   },
    { L_, "\xfe",                         1, IIO,  0,   0   },
    { L_, "\xff",                         1, IIO,  0,   0   },

    // Make sure that the "illegal" UTF-8 octets are handled correctly
    // mid-string:
    //   o The octet values C0, C1, F5 to FF never appear.

    { L_, " \xc0 ",                       3, NCO,  1,   0   },
    { L_, " \xc1 ",                       3, NCO,  1,   0   },
    { L_, " \xf5 ",                       3, NCO,  1,   0   },
    { L_, " \xf6 ",                       3, NCO,  1,   0   },
    { L_, " \xf7 ",                       3, NCO,  1,   0   },
    { L_, " \xf8 ",                       3, IIO,  1,   0   },
    { L_, " \xf9 ",                       3, IIO,  1,   0   },
    { L_, " \xfa ",                       3, IIO,  1,   0   },
    { L_, " \xfb ",                       3, IIO,  1,   0   },
    { L_, " \xfc ",                       3, IIO,  1,   0   },
    { L_, " \xfd ",                       3, IIO,  1,   0   },
    { L_, " \xfe ",                       3, IIO,  1,   0   },
    { L_, " \xff ",                       3, IIO,  1,   0   },

    { L_, U8_00080,                       2,   1, -1,   1   },
    { L_, "\xc2",                         1, EIT,  0,   0   },
    { L_, U8_00080 " ",                   3,   2, -1,   1   },
    { L_, U8_000ff,                       2,   1, -1,   1   },
    { L_, "\x01\x20\x7f" U8_000ff U8_007ff U8_00800 U8_0ffff,
                                         13,   7, -1,   1   },

    { L_, "\x01\x20\x7f" U8_000ff U8_007ff U8_00800 "\xef",
                                         11, EIT, 10,   0   },

    { L_, "\x01\x20\x7f" U8_000ff U8_007ff U8_00800 "\xef\xbf",
                                         12, EIT, 10,   0   },

    { L_, U8_0ffff U8_00800 U8_007ff U8_000ff "\x7f\x20\x01",
                                         13,   7, -1,   1   },

    // Make sure illegal overlong encodings are not accepted.  These code
    // points are mathematically correctly encoded, but since there are
    // equivalent encodings with fewer octets, the UTF-8 standard disallows
    // them.

    { L_, "\xf0\x80\x80\x80",             4, OLE,  0,   0   },
    { L_, "\xf0\x8a\xaa\xaa",             4, OLE,  0,   0   },
    { L_, "\xf0\x8f\xbf\xbf",             4, OLE,  0,   0   },    // max OLE
    { L_, "\xf0\x90\x80\x80",             4,   1,  0,   1   },    // min legal
    { L_, "\xf1\x80\x80\x80",             4,   1,  0,   1   },    // norm legal
    { L_, "\xf1\xaa\xaa\xaa",             4,   1,  0,   1   },    // norm legal
    { L_, "\xf4\x8f\xbf\xbf",             4,   1,  0,   1   },    // max legal
    { L_, "\xf4\x90\x80\x80",             4, VTL,  0,   0   },    // min VTL
    { L_, "\xf4\x90\xbf\xbf",             4, VTL,  0,   0   },    //     VTL
    { L_, "\xf4\xa0\x80\x80",             4, VTL,  0,   0   },    //     VTL
    { L_, "\xf7\xbf\xbf\xbf",             4, VTL,  0,   0   },    // max VTL

    { L_, "\xe0\x80\x80",                 3, OLE,  0,   0   },
    { L_, "\xe0\x9a\xaa",                 3, OLE,  0,   0   },
    { L_, "\xe0\x9f\xbf",                 3, OLE,  0,   0   },    // max OLE
    { L_, "\xe0\xa0\x80",                 3,   1,  0,   1   },    // min legal

    { L_, "\xc0\x80",                     2, OLE,  0,   0   },
    { L_, "\xc0\xaa",                     2, OLE,  0,   0   },
    { L_, "\xc0\xbf",                     2, OLE,  0,   0   },
    { L_, "\xc1\x81",                     2, OLE,  0,   0   },
    { L_, "\xc1\xbf",                     2, OLE,  0,   0   },    // max OLE
    { L_, "\xc2\x80",                     2,   1,  0,   1   },    // min legal

    // Corrupted 2-octet code point:

    { L_, "\xc2",                         1, EIT,  0,   0   },
    { L_, " \xc2",                        2, EIT,  1,   0   },
    { L_, "\xc2 ",                        2, NCO,  0,   0   },
    { L_, "\xc2\xc2",                     2, NCO,  0,   0   },
    { L_, "\xc2\xef",                     2, NCO,  0,   0   },

    // Corrupted 2-octet code point followed by an invalid code point:

    { L_, "\xc2\xff",                     2, NCO,  0,   0   },
    { L_, "\xc2\xff",                     2, NCO,  0,   0   },

    // 3-octet code points corrupted after octet 1:

    { L_, "\xef",                         1, EIT,  0,   0   },
    { L_, " \xef",                        2, EIT,  1,   0   },
    { L_, "\xef ",                        2, NCO,  0,   0   },
    { L_, "\xef\xef ",                    3, NCO,  0,   0   },
    { L_, "\xef \xef",                    3, NCO,  0,   0   },
    { L_, "\xef" U8_00080,                3, NCO,  0,   0   },

    // 3-octet code points corrupted after octet 2:

    { L_, "\xef\xbf",                     2, EIT,  0,   0   },
    { L_, "\xef\xbf",                     2, EIT,  0,   0   },
    { L_, " \xef\xbf@",                   4, NCO,  1,   0   },
    { L_, " \xef\xbf@",                   4, NCO,  1,   0   },
    { L_, "\xef\xbf ",                    3, NCO,  0,   0   },
    { L_, "\xef\xbf ",                    3, NCO,  0,   0   },
    { L_, "\xef\xbf\xef",                 3, NCO,  0,   0   },

    { L_, "\xed\xa0\x80",                 3, SUR,  0,   0   },
    { L_, "\xed\xb0\x85 ",                4, SUR,  0,   0   },
    { L_, "\xed\xbf\xbf",                 3, SUR,  0,   0   },
};
enum { NUM_DATA = sizeof DATA / sizeof *DATA };

// ============================================================================
//                               MAIN PROGRAM
// ----------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    int test = argc > 1 ? bsl::atoi(argv[1]) : 0;

    verbose = argc > 2;
    veryVerbose = argc > 3;
    veryVeryVerbose = argc > 4;
    veryVeryVeryVerbose = argc > 5;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;;

    // CONCERN: 'BSLS_REVIEW' failures should lead to test failures.
    bsls::ReviewFailureHandlerGuard reviewGuard(&bsls::Review::failByAbort);

    switch (test) { case 0:  // Zero is always the leading case.
      case 17: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE 3: 'readIfValid'
        //
        // Concerns:
        //: 1 Demonstrate the 'readIfValid' function.
        //
        // Plan:
        //: 1 Create a function, 'utf8StreambufToString', that uses the
        //:   'readIfValid' function to stream and check UTF-8 from a
        //:   'streambuf' to a 'bsl::string'.
        //:
        //: 2 Stream trivial and non-trivial valid UTF-8 to the string.
        //:
        //: 3 Append invalid UTF-8 to the non-trivial valid UTF-8 string.
        //:
        //: 4 Try to input that with our function and observe that the valid
        //:   UTF-8 preceding the invalid code point gets input, and show how
        //:   the 'status' returned through the argument list of 'readIfValid'
        //:   shows the nature of the UTF-8 error.
        //
        // Testing:
        //   USAGE EXAMPLE 3
        // --------------------------------------------------------------------

        if (verbose) cout << "USAGE EXAMPLE 3: 'readIfValid'\n"
                             "==============================\n";

        using namespace USAGE_3;

        // We decided not to include the following code in the usage example,
        // the function by itself should be enough without its call.  This
        // tests the function.

        bsl::stringstream ss;
        ss << "Hello, world!\n";
        bsl::string out;
        int rc = utf8StreambufToString(&out, ss.rdbuf());
        ASSERT(0 == rc);
        ASSERT("Hello, world!\n" == out);

        static const char validChineseUtf8[] = {
            "\xe4\xb8\xad\xe5\x8d\x8e\xe4\xba\xba\xe6\xb0\x91\xe5\x85\xb1"
            "\xe5\x92\x8c\xe5\x9b\xbd\xef\xbc\x8c\xe9\x80\x9a\xe7\xa7\xb0"
            "\xe4\xb8\xad\xe5\x9b\xbd\x5b\xe6\xb3\xa8\x20\x33\x5d\xef\xbc"
            "\x8c\xe6\x98\xaf\xe4\xbd\x8d\xe6\x96\xbc\xe4\xba\x9a\xe6\xb4"
            "\xb2\xe6\x9d\xb1\xe9\x83\xa8\xe3\x80\x81\xe5\xa4\xaa\xe5\xb9"
            "\xb3\xe6\xb4\x8b\xe8\xa5\xbf\xe5\xb2\xb8\xe7\x9a\x84\xe4\xb8"
            "\x80\xe4\xb8\xaa\xe7\xa4\xbe\xe4\xbc\x9a\xe4\xb8\xbb\xe4\xb9"
            "\x89\xe5\x9b\xbd\xe5\xae\xb6\xe3\x80\x82\xe9\xa6\x96\xe9\x83"
            "\xbd\xe7\x82\xba\xe5\x8c\x97\xe4\xba\xac\xe3\x80\x82\xe5\x85"
            "\xb6\xe9\x99\x86\xe5\x9c\xb0\xe7\x96\x86\xe5\x9f\x9f\xe8\x88"
            "\x87\xe5\x91\xa8\xe9\x82\x8a\x31\x34\xe5\x80\x8b\xe5\x9c\x8b"
            "\xe5\xae\xb6\xe6\x8e\xa5\xe5\xa3\xa4\xef\xbc\x8c\xe9\x99\x86"
            "\xe5\x9c\xb0\xe5\x8f\x8a\xe6\xb9\x96\xe6\xb3\x8a\xe7\x9a\x84"
            "\xe6\x80\xbb\xe9\x9d\xa2\xe7\xa9\x8d\xe7\xba\xa6\x39\x36\x30"
            "\xe8\x90\xac\xe5\xb9\xb3\xe6\x96\xb9\xe5\x85\xac\xe9\x87\x8c"
            "\x5b\x31\x31\x5d\x5b\x31\x32\x5d\x5b\x31\x33\x5d\xef\xbc\x8c"
            "\xe6\x98\xaf\xe5\x85\xa8\xe4\xb8\x96\xe7\x95\x8c\xe9\x99\x86"
            "\xe5\x9c\xb0" };
        const bsl::size_t validLen = sizeof(validChineseUtf8) - 1;

        if (verbose) cout << "Length of Chinese string: " << validLen << endl;
        if (veryVerbose) cout << validChineseUtf8 << endl;

        ss.str("");
        ss << validChineseUtf8;
        rc = utf8StreambufToString(&out, ss.rdbuf());
        ASSERT(0 == rc);
        ASSERT(validChineseUtf8 == out);

        bsl::string invalidUtf8Str(validChineseUtf8);
        invalidUtf8Str += "\xaf Keep cool with Coolidge!";

        ss.str("");
        ss << invalidUtf8Str;
        rc = utf8StreambufToString(&out, ss.rdbuf());
        ASSERT(rc != 0);
        ASSERT(invalidUtf8Str != out);
        ASSERT(out.length() == validLen);
        ASSERT(validChineseUtf8 == out);
      } break;
      case 16: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE 2: 'advance'
        //
        // Concerns:
        //: 1 Demonstrate the 'advance*' functions.
        //
        // Plan:
        //: 1 Use the 'appendUtf8CodePoint' function to build an example
        //:   string, then advance through it.
        //
        // Testing:
        //   USAGE EXAMPLE 2
        // --------------------------------------------------------------------

        if (verbose) cout << "USAGE EXAMPLE 2: 'advance'\n"
                             "==========================\n";

//
///Example 2: Advancing Over a Given Number of Code Points
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we will use the various 'advance' functions to advance
// through a UTF-8 string.
//
// First, build the string using 'appendUtf8CodePoint', keeping track of how
// many bytes are in each Unicode code point:
//..
    bsl::string string;
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0xff00);        // 3 bytes
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x1ff);         // 2 bytes
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 'a');           // 1 byte
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x1008aa);      // 4 bytes
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x1abcd);       // 4 bytes
    string += "\xe3\x8f\xfe";           // 3 bytes (invalid 3-byte sequence,
                                        // the first 2 bytes are valid but the
                                        // last continuation byte is invalid)
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 'w');           // 1 byte
    bdlde::Utf8Util::appendUtf8CodePoint(&string, '\n');          // 1 byte
//..
// Then, declare a few variables we'll need:
//..
    bsls::Types::IntPtr  rc;
    int                  status;
    const char          *result;
    const char *const start = string.c_str();
//..
// Next, try advancing 2 code points, then 3, then 4, observing that the value
// returned is the number of Unicode code points advanced.  Note that since
// we're only advancing over valid UTF-8, we can use either 'advanceRaw' or
// 'advanceIfValid':
//..
    rc = bdlde::Utf8Util::advanceRaw(              &result, start, 2);
    ASSERT(2 == rc);
    ASSERT(3 + 2 == result - start);

    rc = bdlde::Utf8Util::advanceIfValid(&status, &result, start, 2);
    ASSERT(0 == status);
    ASSERT(2 == rc);
    ASSERT(3 + 2 == result - start);

    rc = bdlde::Utf8Util::advanceRaw(             &result, start, 3);
    ASSERT(3 == rc);
    ASSERT(3 + 2 + 1 == result - start);

    rc = bdlde::Utf8Util::advanceIfValid(&status, &result, start, 3);
    ASSERT(0 == status);
    ASSERT(3 == rc);
    ASSERT(3 + 2 + 1 == result - start);

    rc = bdlde::Utf8Util::advanceRaw(             &result, start, 4);
    ASSERT(4 == rc);
    ASSERT(3 + 2 + 1 + 4 == result - start);

    rc = bdlde::Utf8Util::advanceIfValid(&status, &result, start, 4);
    ASSERT(0 == status);
    ASSERT(4 == rc);
    ASSERT(3 + 2 + 1 + 4 == result - start);
//..
// Then, try advancing by more code points than are present using
// 'advanceIfValid', and wind up stopping when we encounter invalid input.  The
// behavior of 'advanceRaw' is undefined if it is used on invalid input, so we
// cannot use it here.  Also note that we will stop at the beginning of the
// invalid Unicode code point, and not at the first incorrect byte, which is
// two bytes later:
//..
    rc = bdlde::Utf8Util::advanceIfValid(&status, &result, start, INT_MAX);
    ASSERT(0 != status);
    ASSERT(5 == rc);
    ASSERT(3 + 2 + 1 + 4 + 4                 == result - start);
    ASSERT(static_cast<int>(string.length()) >  result - start);
//..
// Now, doctor the string to replace the invalid code point with a valid one,
// so the string is entirely correct UTF-8:
//..
    string[3 + 2 + 1 + 4 + 4 + 2] = static_cast<char>(0x8a);
//..
// Finally, advance using both functions by more code points than are in the
// string and in both cases wind up at the end of the string.  Note that
// 'advanceIfValid' does not return an error (non-zero) value to 'status' when
// it encounters the end of the string:
//..
    rc = bdlde::Utf8Util::advanceRaw(             &result, start, INT_MAX);
    ASSERT(8 == rc);
    ASSERT(3 + 2 + 1 + 4 + 4 + 3 + 1 + 1     == result - start);
    ASSERT(static_cast<int>(string.length()) == result - start);

    rc = bdlde::Utf8Util::advanceIfValid(&status, &result, start, INT_MAX);
    ASSERT(0 == status);
    ASSERT(8 == rc);
    ASSERT(3 + 2 + 1 + 4 + 4 + 3 + 1 + 1     == result - start);
    ASSERT(static_cast<int>(string.length()) == result - start);
//..
      } break;
      case 15: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE 1: 'isValid' AND 'numCodePoints*'
        //
        // Concerns:
        //: 1 Demonstrate the routines by encoding some UTF-8 strings and
        //:   validating them and counting their code points.
        //
        // Plan:
        //: 1 Create both UTF-8 and modified UTF-8 strings and validate them.
        //
        // Testing:
        //   USAGE EXAMPLE 1
        // --------------------------------------------------------------------

        if (verbose) cout <<
                           "USAGE EXAMPLE 1: 'isValid' AND 'numCodePoints*'\n"
                           "===============================================\n";

///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Validating Strings and Counting Unicode Code Points
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this usage example, we will encode some Unicode code points in UTF-8
// strings and demonstrate those that are valid and those that are not.
//
// First, we build an unquestionably valid UTF-8 string:
//..
    bsl::string string;
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0xff00);
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x856);
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 'a');
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x1008aa);
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0xfff);
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 'w');
    bdlde::Utf8Util::appendUtf8CodePoint(&string, 0x1abcd);
    bdlde::Utf8Util::appendUtf8CodePoint(&string, '.');
    bdlde::Utf8Util::appendUtf8CodePoint(&string, '\n');
//..
// Then, we check its validity and measure its length:
//..
    ASSERT(true == bdlde::Utf8Util::isValid(string.data(), string.length()));
    ASSERT(true == bdlde::Utf8Util::isValid(string.c_str()));

    ASSERT(   9 == bdlde::Utf8Util::numCodePointsRaw(string.data(),
                                                     string.length()));
    ASSERT(   9 == bdlde::Utf8Util::numCodePointsRaw(string.c_str()));
//..
// Next, we encode a lone surrogate value, '0xd8ab', that we encode as the raw
// 3-byte sequence "\xed\xa2\xab" to avoid validation:
//..
    bsl::string stringWithSurrogate = string + "\xed\xa2\xab";
//..
    ASSERT(false == bdlde::Utf8Util::isValid(stringWithSurrogate.data(),
                                             stringWithSurrogate.length()));
    ASSERT(false == bdlde::Utf8Util::isValid(stringWithSurrogate.c_str()));
//..
// Then, we cannot use 'numCodePointsRaw' to count the code points in
// 'stringWithSurrogate', since the behavior of that method is undefined unless
// the string is valid.  Instead, the 'numCodePointsIfValid' method can be used
// on strings whose validity we are uncertain of:
//..
    const char *invalidPosition = 0;

    bsls::Types::IntPtr rc;
    rc = bdlde::Utf8Util::numCodePointsIfValid(&invalidPosition,
                                               stringWithSurrogate.data(),
                                               stringWithSurrogate.length());
    ASSERT(rc < 0);
    ASSERT(bdlde::Utf8Util::k_SURROGATE == rc);
    ASSERT(invalidPosition == stringWithSurrogate.data() + string.length());

    invalidPosition = 0;  // reset

    rc = bdlde::Utf8Util::numCodePointsIfValid(&invalidPosition,
                                               stringWithSurrogate.c_str());
    ASSERT(rc < 0);
    ASSERT(bdlde::Utf8Util::k_SURROGATE == rc);
    ASSERT(invalidPosition == stringWithSurrogate.data() + string.length());
//..
// Now, we encode 0, which is allowed.  However, note that we cannot use any
// interfaces that take a null-terminated string for this case:
//..
    bsl::string stringWithNull = string;
    stringWithNull += '\0';
//..
    ASSERT(true == bdlde::Utf8Util::isValid(stringWithNull.data(),
                                            stringWithNull.length()));

    ASSERT(  10 == bdlde::Utf8Util::numCodePointsRaw(stringWithNull.data(),
                                                     stringWithNull.length()));
//..
// Finally, we encode '0x3a' (':') as an overlong value using 2 bytes, which is
// not valid UTF-8 (since ':' can be "encoded" in 1 byte):
//..
    bsl::string stringWithOverlong = string;
    stringWithOverlong += static_cast<char>(0xc0);        // start of 2-byte
                                                          // sequence
    stringWithOverlong += static_cast<char>(0x80 | ':');  // continuation byte

    ASSERT(false == bdlde::Utf8Util::isValid(stringWithOverlong.data(),
                                             stringWithOverlong.length()));
    ASSERT(false == bdlde::Utf8Util::isValid(stringWithOverlong.c_str()));

    rc = bdlde::Utf8Util::numCodePointsIfValid(&invalidPosition,
                                               stringWithOverlong.data(),
                                               stringWithOverlong.length());
    ASSERT(rc < 0);
    ASSERT(bdlde::Utf8Util::k_OVERLONG_ENCODING == rc);
    ASSERT(invalidPosition == stringWithOverlong.data() + string.length());

    rc = bdlde::Utf8Util::numCodePointsIfValid(&invalidPosition,
                                               stringWithOverlong.c_str());
    ASSERT(rc < 0);
    ASSERT(bdlde::Utf8Util::k_OVERLONG_ENCODING == rc);
    ASSERT(invalidPosition == stringWithOverlong.data() + string.length());
//..
      } break;
      case 14: {
        // --------------------------------------------------------------------
        // NEGATIVE TESTING
        //
        // Concern:
        //: 1 That all the functions in this component properly assert their
        //:   preconditions to avoid undefined behavior.
        //:
        //: 2 That those functions that take their input as a string pointer,
        //:   length pair will tolerate being passed a null pointer when the
        //:   length is 0, and will not tolerate being passed a null pointer
        //:   when '0 < length'.
        //
        // Plan:
        //: 1 Go through every function in the component, first calling them in
        //:   such a way that they function properly, then calling them with
        //:   every possible pointer argument passed null when it shouldn't be,
        //:   and confirm that this is caught in an assert using the
        //:   'bsls_asserttest' component.
        //:
        //: 2 For the functions that take their input as a 'ptr, length' pair,
        //:   call them with null ptrs while passing a 0 to the 'length' field
        //:   and verify that the function works properly, then pass it exactly
        //:   the same arguments except with the 'length == 1', and observe
        //:   that this is caught with an exception.
        //
        // Testing:
        //   NEGATIVE TESTING
        // --------------------------------------------------------------------

        if (verbose) cout << "NEGATIVE TESTING\n"
                             "================\n";

#ifdef BDE_BUILD_TARGET_EXC
        {
            const int                     INIT_INT = 123454321;      // garbage
            const char           * const  INIT_RESULT = "woof";      // garbage

            bsls::AssertTestHandlerGuard  guard;
            int                           status = INIT_INT;
            const char                   *result = INIT_RESULT;
            const char           * const  nullStr = 0;
            IntPtr                        rc;

            const char            * const WOOF = "woof";

            for (int ncp = 0; ncp < 2; ++ncp) {
                const int NCP = ncp;    // num code points

                if (veryVerbose) {
                    cout << "advanceIfValid - no length, NCP: " << NCP << "\n";
                }
                {
                    ASSERT_PASS(rc = Obj::advanceIfValid(&status, &result,
                                                                   WOOF, NCP));
                    ASSERT(NCP == rc);
                    ASSERT(0 == status);
                    ASSERT(WOOF + NCP == result);

                    rc     = INIT_INT;
                    status = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_FAIL(Obj::advanceIfValid(0, &result, WOOF, NCP));
                    ASSERT(INIT_INT == status);

                    ASSERT_FAIL(Obj::advanceIfValid(&status, 0, WOOF, NCP));
                    ASSERT(INIT_INT == status);

                    ASSERT_FAIL(Obj::advanceIfValid(&status, &result, nullStr,
                                                                         NCP));
                    ASSERT(INIT_INT == status);
                    ASSERT(INIT_RESULT == result);
                }

                if (veryVerbose) {
                    cout << "advanceIfValid - with length, NCP: " << NCP <<
                                                                          "\n";
                }
                {
                    rc     = INIT_INT;
                    status = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_PASS(rc = Obj::advanceIfValid(&status, &result,
                                                                WOOF, 4, NCP));
                    ASSERT(NCP == rc);
                    ASSERT(0 == status);
                    ASSERT(WOOF + NCP == result);

                    rc     = INIT_INT;
                    status = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_PASS(rc = Obj::advanceIfValid(&status, &result,
                                                             nullStr, 0, NCP));
                    ASSERT(0 == rc);
                    ASSERT(0 == status);
                    ASSERT(0 == result);

                    rc     = INIT_INT;
                    status = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_FAIL(Obj::advanceIfValid(&status, &result, nullStr,
                                                                      1, NCP));
                    ASSERT(INIT_INT == status);
                    ASSERT(INIT_RESULT == result);

                    ASSERT_FAIL(Obj::advanceIfValid(0, &result, WOOF, 4, NCP));
                    ASSERT(INIT_RESULT == result);

                    ASSERT_FAIL(Obj::advanceIfValid(&status, 0, WOOF, 4, NCP));
                    ASSERT(INIT_INT == status);
                }

                if (veryVerbose) {
                    cout << "advanceRaw - no length, NCP: " << NCP << "\n";
                }
                {
                    ASSERT_PASS(rc = Obj::advanceRaw(&result, WOOF, NCP));
                    ASSERT(NCP == rc);
                    ASSERT(WOOF + NCP == result);

                    rc     = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_FAIL(Obj::advanceRaw(0, WOOF, NCP));

                    ASSERT_FAIL(Obj::advanceRaw(&result, nullStr, NCP));
                    ASSERT(INIT_RESULT == result);

                    result = INIT_RESULT;
                }

                if (veryVerbose) {
                    cout << "advanceRaw - with length, NCP: " << NCP << "\n";
                }
                {
                    ASSERT_PASS(rc = Obj::advanceRaw(&result, WOOF, 4, NCP));
                    ASSERT(NCP == rc);
                    ASSERT(WOOF + NCP == result);

                    rc     = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_PASS(rc =
                                    Obj::advanceRaw(&result, nullStr, 0, NCP));
                    ASSERT(0 == rc);
                    ASSERT(0 == result);

                    rc     = INIT_INT;
                    result = INIT_RESULT;

                    ASSERT_FAIL(Obj::advanceRaw(0, WOOF, 4, NCP));

                    ASSERT_FAIL(Obj::advanceRaw(&result, nullStr, 1, NCP));
                }
            }

            if (verbose) cout << "appendUtf8CodePoint\n";
            {
                bsl::string s;
                ASSERT_PASS(rc = Obj::appendUtf8CodePoint(&s, 'a'));
                ASSERT(0 == rc);
                ASSERT("a" == s);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::appendUtf8CodePoint(
                                          static_cast<bsl::string *>(0), 'a'));
            }

            if (verbose) cout << "appendUtf8Character\n";
            {
                bsl::string s;
                ASSERT_PASS(rc = Obj::appendUtf8Character(&s, 'a'));
                ASSERT(0 == rc);
                ASSERT("a" == s);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::appendUtf8Character(
                                          static_cast<bsl::string *>(0), 'a'));
            }

            if (verbose) cout << "numBytesInCodePoint\n";
            {
                ASSERT_PASS(rc = Obj::numBytesInCodePoint(WOOF));
                ASSERT(1 == rc);

                ASSERT_FAIL(Obj::numBytesInCodePoint(nullStr));
            }

            if (verbose) cout << "getByteSize\n";
            {
                ASSERT_PASS(rc = Obj::getByteSize(WOOF));
                ASSERT(1 == rc);

                ASSERT_FAIL(Obj::getByteSize(nullStr));
            }

            if (verbose) cout << "isValid -- no length\n";
            {
                ASSERT_PASS(rc = Obj::isValid(WOOF));
                ASSERT(1 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::isValid(nullStr));
            }

            if (verbose) cout << "isValid -- with length\n";
            {
                ASSERT_PASS(rc = Obj::isValid(WOOF, 4));
                ASSERT(1 == rc);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::isValid(nullStr, 0));
                ASSERT(1 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::isValid(nullStr, 1));
            }

            if (verbose) cout << "isValid -- with result, no length\n";
            {
                ASSERT_PASS(rc = Obj::isValid(&result, WOOF));
                ASSERT(1 == rc);
                ASSERT(INIT_RESULT == result);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::isValid(&result, nullStr));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "isValid -- with result and length\n";
            {
                ASSERT_PASS(rc = Obj::isValid(&result, WOOF, 4));
                ASSERT(1 == rc);
                ASSERT(INIT_RESULT == result);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::isValid(&result, nullStr, 0));
                ASSERT(1 == rc);
                ASSERT(INIT_RESULT == result);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::isValid(0, WOOF, 4));

                ASSERT_FAIL(Obj::isValid(&result, nullStr, 1));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "numCharacters -- no length\n";
            {
                ASSERT_PASS(rc = Obj::numCharacters(WOOF));
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCharacters(nullStr));
            }

            if (verbose) cout << "numCharacters -- with length\n";
            {
                ASSERT_PASS(rc = Obj::numCharacters(WOOF, 4));
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::numCharacters(nullStr, 0));
                ASSERT(0 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCharacters(nullStr, 1));
            }

            if (verbose) cout << "numCharactersIfValid -- no length\n";
            {
                ASSERT_PASS(rc = Obj::numCharactersIfValid(&result, WOOF));
                ASSERT(INIT_RESULT == result);
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCharactersIfValid(0, WOOF));

                ASSERT_FAIL(Obj::numCharactersIfValid(&result, nullStr));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "numCharactersIfValid -- with length\n";
            {
                ASSERT_PASS(rc = Obj::numCharactersIfValid(&result, WOOF, 4));
                ASSERT(INIT_RESULT == result);
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::numCharactersIfValid(&result, nullStr,
                                                                           0));
                ASSERT(0 == rc);
                ASSERT(INIT_RESULT == result);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCharactersIfValid(0, WOOF, 4));

                ASSERT_FAIL(Obj::numCharactersIfValid(&result, nullStr, 1));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "numCodePointsRaw -- no length\n";
            {
                ASSERT_PASS(rc = Obj::numCodePointsRaw(WOOF));
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCodePointsRaw(nullStr));

                for (int i = 1; i <= 255; ++i) {
                    char buf[5] = { char(i), '*', '*', '*', 0 };
                    for (int j = 4; j > 0; --j) {
                        buf[j] = 0;
                        if (veryVeryVerbose) { T_ P_(i) P_(j) P(buf) }
                        if (j >= "1111111144442234"[i >> 4] - '0') {
                            ASSERT_PASS(rc = Obj::numCodePointsRaw(buf));
                            ASSERT(1 <= rc);
                        }
                        else {
                            ASSERT_FAIL(rc = Obj::numCodePointsRaw(buf));
                        }
                    }
                }
            }

            if (verbose) cout << "numCodePointsRaw -- with length\n";
            {
                ASSERT_PASS(rc = Obj::numCodePointsRaw(WOOF, 4));
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::numCodePointsRaw(nullStr, 0));
                ASSERT(0 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCodePointsRaw(nullStr, 1));

                for (int i = 0; i <= 255; ++i) {
                    char buf[4] = { char(i), '*', '*', '*' };
                    for (int j = 4; j > 0; --j) {
                        if (veryVeryVerbose) { T_ P_(i) P_(j) P(buf) }
                        if (j >= "1111111144442234"[i >> 4] - '0') {
                            ASSERT_PASS(rc = Obj::numCodePointsRaw(buf, j));
                            ASSERT(1 <= rc);
                        }
                        else {
                            ASSERT_FAIL(rc = Obj::numCodePointsRaw(buf, j));
                        }
                    }
                }
            }

            if (verbose) cout << "numCodePointsIfValid -- no length\n";
            {
                ASSERT_PASS(rc = Obj::numCodePointsIfValid(&result, WOOF));
                ASSERT(INIT_RESULT == result);
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCodePointsIfValid(0, WOOF));

                ASSERT_FAIL(Obj::numCodePointsIfValid(&result, nullStr));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "numCodePointsIfValid -- with length\n";
            {
                ASSERT_PASS(rc = Obj::numCodePointsIfValid(&result, WOOF, 4));
                ASSERT(INIT_RESULT == result);
                ASSERT(4 == rc);

                rc     = INIT_INT;

                ASSERT_PASS(rc = Obj::numCodePointsIfValid(&result, nullStr,
                                                                           0));
                ASSERT(0 == rc);
                ASSERT(INIT_RESULT == result);

                rc     = INIT_INT;

                ASSERT_FAIL(Obj::numCodePointsIfValid(0, WOOF, 4));

                ASSERT_FAIL(Obj::numCodePointsIfValid(&result, nullStr, 1));
                ASSERT(INIT_RESULT == result);
            }

            if (verbose) cout << "readIfValid\n";
            {
                bdlsb::FixedMemInStreamBuf fsb("woof", 4);
                char buf[4] = { "ugh" };
                const bsl::string UGH = buf;

                ASSERT_PASS(rc = Obj::readIfValid(&status, buf, 4, &fsb));
                ASSERT(1 == rc);
                ASSERT(0 < status);
                buf[rc] = 0;
                ASSERT(!bsl::strcmp("w", buf));
                ASSERT(1 == fsb.pubseekoff(0, bsl::ios_base::cur));

                rc     = INIT_INT;
                status = INIT_INT;
                bsl::strcpy(buf, UGH.c_str());
                fsb.pubseekpos(0);

                ASSERT_FAIL(Obj::readIfValid(0, buf, 4, &fsb));
                ASSERT(0 == fsb.pubseekoff(0, bsl::ios_base::cur));
                ASSERT(UGH == buf);

                ASSERT_FAIL(Obj::readIfValid(&status, 0, 4, &fsb));
                ASSERT(0 == fsb.pubseekoff(0, bsl::ios_base::cur));
                ASSERT(UGH == buf);
                ASSERT(INIT_INT == status);

                ASSERT_FAIL(Obj::readIfValid(&status, buf, 3, &fsb));
                ASSERT(0 == fsb.pubseekoff(0, bsl::ios_base::cur));
                ASSERT(UGH == buf);
                ASSERT(INIT_INT == status);

                ASSERT_FAIL(Obj::readIfValid(&status, buf, 4, 0));
                ASSERT(UGH == buf);
                ASSERT(INIT_INT == status);
            }
        }
#endif
      } break;
      case 13: {
        // --------------------------------------------------------------------
        // TESTING 'toAscii'
        //
        // Concerns:
        //: 1 That 'toAscii' correctly translates 'ErrorStatus' values to
        //:   strings.
        //
        // Plan:
        //: 1 Create a table of all valid 'ErrorStatus' values and their
        //:   expected string forms.
        //:
        //: 2 Iterate through the table, calling 'toAscii' and checking its
        //:   return value.
        //
        // Testing:
        //   const char *toAscii(IntPtr);
        // --------------------------------------------------------------------

        if (verbose) cout << "TESTING 'toAscii'\n"
                             "=================\n";

        static const char *NOT_FOUND = "(* unrecognized value *)";

        static const struct Data {
            IntPtr      d_status;
            const char *d_expStr_p;
        } DATA[] = {
          { Obj::k_END_OF_INPUT_TRUNCATION,    "END_OF_INPUT_TRUNCATION" },
          { Obj::k_UNEXPECTED_CONTINUATION_OCTET,
                                              "UNEXPECTED_CONTINUATION_OCTET"},
          { Obj::k_NON_CONTINUATION_OCTET,     "NON_CONTINUATION_OCTET" },
          { Obj::k_OVERLONG_ENCODING,          "OVERLONG_ENCODING" },
          { Obj::k_INVALID_INITIAL_OCTET,      "INVALID_INITIAL_OCTET" },
          { Obj::k_VALUE_LARGER_THAN_0X10FFFF, "VALUE_LARGER_THAN_0X10FFFF" },
          { Obj::k_SURROGATE,                  "SURROGATE" },
          { 0,                                 NOT_FOUND },
          { 1,                                 NOT_FOUND },
          { 100,                               NOT_FOUND },
          { Obj::k_END_OF_INPUT_TRUNCATION+1,  NOT_FOUND },
          { Obj::k_SURROGATE - 1,              NOT_FOUND },
          { 100,                               NOT_FOUND },
          { -100,                              NOT_FOUND },
          { INT_MAX,                           NOT_FOUND },
          { INT_MIN,                           NOT_FOUND },
          { LONG_MAX,                          NOT_FOUND },
          { LONG_MIN,                          NOT_FOUND }
        };
        enum { k_NUM_DATA = sizeof DATA / sizeof *DATA };

        for (int ti = 0; ti < k_NUM_DATA; ++ti) {
            const IntPtr      STATUS  = DATA[ti].d_status;
            const bsl::string EXP_STR = DATA[ti].d_expStr_p;

            ASSERT(EXP_STR == Obj::toAscii(STATUS));
        }
      } break;
      case 12: {
        // --------------------------------------------------------------------
        // TESTING 'appendUtf8CodePoint'
        //
        // Concerns:
        //: 1 The method under test produce the expected results on valid
        //:   code points.  The principal concern is that the append is
        //:   performed correctly.
        //
        // Plan:
        //: 1 Use the table-driven approach to verify correct behavior when
        //:   appending various valid code points to both empty and non-empty
        //:   strings.  This is sufficient since the routine under test is
        //:   implemented in terms of an already tested component.
        //
        // Testing:
        //   int appendUtf8CodePoint(bsl::string *, unsigned int);
        //   int appendUtf8Character(bsl::string *, unsigned int);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING 'appendUtf8CodePoint'\n"
                               "=============================\n";

        for (int ti = 0; ti < NUM_INTERESTING_CODEPOINTS; ++ti) {
            const int     LINE      = legalCodepointData[ti].d_lineNum;
            const char   *UTF8      = legalCodepointData[ti].d_utf8_p;
            bsl::size_t   UTF8_LEN  = strlen(UTF8);
            unsigned int  CODEPOINT = legalCodepointData[ti].d_codePoint;

            bsl::string   empty;
            bsl::string   non_empty("Not an empty string");
            bsl::size_t   non_empty_init_len = non_empty.length();

            if (veryVerbose) {
                T_; P_(ti);
                P_(LINE); P_(dumpStr(UTF8)); P_(UTF8_LEN); P(CODEPOINT);
            }

            ASSERT(0 == Obj::appendUtf8CodePoint(&empty, CODEPOINT));
            ASSERT(UTF8_LEN == empty.length());

            ASSERT(0 == Obj::appendUtf8CodePoint(&non_empty, CODEPOINT));
            ASSERT(non_empty_init_len + UTF8_LEN == non_empty.length());

            empty.clear();
            non_empty.resize(non_empty_init_len);

            ASSERT(0 == Obj::appendUtf8Character(&empty, CODEPOINT));
            ASSERT(UTF8_LEN == empty.length());

            ASSERT(0 == Obj::appendUtf8Character(&non_empty, CODEPOINT));
            ASSERT(non_empty_init_len + UTF8_LEN == non_empty.length());
        }
      } break;
      case 11: {
        // --------------------------------------------------------------------
        // TESTING 'numBytesInCodePoint'
        //
        // Concerns:
        //: 1 The method under test produce the expected results on valid UTF-8
        //:   code points.
        //
        // Plan:
        //: 1 Use the table-driven approach to verify correct behavior on
        //:   various valid UTF-8 code points.
        //
        // Testing:
        //   int numBytesInCodePoint(const char *);
        //   int getByteSize(const char *);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING 'numBytesInCodePoint'\n"
                               "=============================\n";

        for (int ti = 0; ti < NUM_INTERESTING_CODEPOINTS; ++ti) {
            const int    LINE     = legalCodepointData[ti].d_lineNum;
            const char  *UTF8     = legalCodepointData[ti].d_utf8_p;
            bsl::size_t  UTF8_LEN = strlen(UTF8);

            if (veryVerbose) {
                T_; P_(ti);
                P_(LINE); P_(dumpStr(UTF8)); P(UTF8_LEN);
            }

            ASSERT(int(UTF8_LEN) == Obj::numBytesInCodePoint(UTF8));
            ASSERT(int(UTF8_LEN) == Obj::getByteSize(UTF8));
        }
      } break;
      case 10: {
        // --------------------------------------------------------------------
        // TESTING 'numBytesRaw'
        //
        // Concerns:
        //: 1 The method under test produce the expected results on valid UTF-8
        //:   strings whether or not embedded '\0' characters are present.
        //
        // Plan:
        //: 1 Use the table-driven approach to verify correct behavior on
        //:   various valid UTF-8 strings.  Append a '\0' to each candidate
        //:   string, then repeat appending each table entry again.
        //
        // Testing:
        //   IntPtr numBytesRaw(const bslstl::StringRef&, IntPtr);
        //   IntPtr numBytesIfValid(const bslstl::StringRef&, IntPtr);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING 'numBytesRaw'\n"
                               "=====================\n";

        for (int ti = 0; ti < NUM_INTERESTING_CODEPOINTS; ++ti) {
            const int         LINE = legalCodepointData[ti].d_lineNum;
            const bsl::string UTF8 = legalCodepointData[ti].d_utf8_p;

            if (veryVerbose) {
                T_; P_(ti);
                P_(LINE); P_(dumpStr(UTF8)); P(UTF8.length());
            }

            ASSERT(Obj::IntPtr(UTF8.length()) ==
                   Obj::numBytesRaw(UTF8, 1));

            ASSERT(Obj::IntPtr(UTF8.length()) ==
                   Obj::numBytesIfValid(UTF8, 1));

            for (int tj = 0; tj < NUM_INTERESTING_CODEPOINTS; ++tj) {
                const int   LINE_2 = legalCodepointData[tj].d_lineNum;
                bsl::string UTF8_2 = UTF8;

                UTF8_2.push_back(0);
                UTF8_2 += legalCodepointData[tj].d_utf8_p;

                if (veryVeryVerbose) {
                    T_; T_; P_(tj);
                    P_(LINE_2); P_(dumpStr(UTF8_2)); P(UTF8_2.length());
                }

                // Adding 2nd code point doesn't change the answer if we only
                // ask for the 1st code point's byte length.
                ASSERT(Obj::IntPtr(UTF8.length()) ==
                       Obj::numBytesRaw(UTF8_2, 1));

                // Embedded nulls count as 1 byte.
                ASSERT(1 + Obj::IntPtr(UTF8.length()) ==
                       Obj::numBytesRaw(UTF8_2, 2));

                ASSERT(Obj::IntPtr(UTF8_2.length()) ==
                       Obj::numBytesRaw(UTF8_2, 3));

                // Adding 2nd code point doesn't change the answer if we only
                // ask for the 1st code point's byte length.
                ASSERT(Obj::IntPtr(UTF8.length()) ==
                       Obj::numBytesIfValid(UTF8_2, 1));

                // Embedded nulls count as 1 byte.
                ASSERT(1 + Obj::IntPtr(UTF8.length()) ==
                       Obj::numBytesIfValid(UTF8_2, 2));

                ASSERT(Obj::IntPtr(UTF8_2.length()) ==
                       Obj::numBytesIfValid(UTF8_2, 3));
            }
        }
      } break;
      case 9: {
        // --------------------------------------------------------------------
        // TESTING CORRECT + BROKEN GLASS
        //
        // CONCERN:
        //: 1 That 'advanceIfValid' will detect all forms of error sequences
        //:   and properly terminate and report them, when the incorrect
        //:   sequences are surrounded by correct UTF-8.
        //:
        //: 2 That 'advanceIfValid', 'isValid', 'numCodePointsIfValid', and
        //:   'readIfValid' will, given invalid UTF-8 embedded in a string,
        //:   correctly identify the nature of the invalid UTF-8, and in cases
        //:   where the offset of the problem is returned, will return the
        //:   correct offset.
        //:
        //: 3 In the case of 'readIfValid', that it will leave the input
        //:   'bsl::streambuf' positioned right after the end of the leading
        //:   valid UTF-8 (if any) and before the invalid UTF-8 code point.
        //
        // PLAN:
        //: 1 In this test case, we test incorrect UTF-8 sequences both
        //:   preceded by, and sometimes followed by, correct UTF-8 input.
        //:
        //: 2 We set the boolean 'useZero', which indicates whether our random
        //:   value generation is allowed to generate ASCII '\0' bytes in
        //:   otherwise correct UTF-8 input.  We don't want to do this most of
        //:   the time, since it precludes calling interfaces that take
        //:   null-terminated input.
        //:
        //: 3 We randomly generate 'correctStr', several random correct UTF-8
        //:   code points.
        //:
        //: 4 We iterate over the global 'DATA[]' array, skipping the sequences
        //:   of correct UTF-8 in it, focusing instead on only the incorrect
        //:   sequences.
        //:
        //: 5 We look at ERROR_CODE, the expected error code for the invalid
        //:   UTF-8 sequence.  It it's 'EIT' (end of buffer truncation), we
        //:   generate a random valid UTF-8 sequence of the same type and
        //:   truncate it by the same amount.  For other values of ERROR_CODE,
        //:   we simply use the error string from 'DATA[]'.  In either case, we
        //:   append this error string to 'str', the test string.
        //:
        //: 6 If there are no embedded '\0's in the input, we call all
        //:   overloads of 'advanceIfValid', 'isValid' and
        //:   'numCodePointsIfValid' that take null-terminated strings, and
        //:   observe that they return a status of 'ERROR_CODE' and if they
        //:   return 'invalidString', that 'invalidString' is correct.
        //:
        //: 7 We then call all overloads of 'advanceIfValid', 'isValid',
        //:   'numCodePointsIfValid', and 'readValidUtf8ToBuffer' that pass the
        //:   length of the string, and confirm that they return the error code
        //:   'ERROR_CODE'.  If there are no embedded '\0's in 'str', we also
        //:   call the overloads that take null-terminated input.
        //:
        //: 8 We then append a valid code point to 'str'.  If 'ERROR_CODE' was
        //:   'EIT' (end of buffer truncation), we change 'ERROR_CODE' to 'NCO'
        //:   (non-continuation octet).
        //:
        //: 9 We now repeat step '6'.
        //
        // Testing:
        //   IntPtr advanceIfValid(int *, cchar **,  cchar *, IntPtr);
        //   IntPtr advanceIfValid(int *, cchar **, cchar *, size_t, IntPtr);
        //   bool isValid(cchar *);
        //   bool isValid(cchar *, size_t);
        //   bool isValid(cchar **, cchar *);
        //   bool isValid(cchar **, cchar *, size_t);
        //   IntPtr numCodePointsIfValid(cchar **, cchar *);
        //   IntPtr numCodePointsIfValid(cchar **, const char *, int);
        //   IntPtr numCodePointsIfValid(cchar **, cchar *, IntPtr);
        //   IntPtr readIfValid(int *, cchar *, size_t, streambuf *);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING CORRECT + BROKEN GLASS\n"
                               "==============================\n";

        bsl::string      correctStr;
        bsl::string      str, errorStr, out;

        const IntPtr INT_PTR_MAX = ~static_cast<bsl::size_t>(0) >> 1;

        enum { k_NUM_ITERATIONS          = 800,
               k_NUM_USE_ZERO_ITERATIONS = k_NUM_ITERATIONS / 10,
               k_MAX_INPUT_LEN           = 200 };

        correctStr.reserve(k_MAX_INPUT_LEN);    // reserve longer than the
                                                // longest length we will use,
                                                // so no manipulation of this
                                                // 'string' will result in a
                                                // reallocation and a move of
                                                // the buffer.

        str.reserve(k_MAX_INPUT_LEN + 10);      // enough room to copy
                                                // 'correctStr' and tack some
                                                // carnage on to the end of it.

        out.reserve(k_MAX_INPUT_LEN + 14);      // enough room for output from
                                                // str
        errorStr.reserve(200);

        const char badChar = static_cast<char>(0xf8);    // always illegal char

        bdlsb::FixedMemInStreamBuf fsb(0, 0);

        for (int tj = 0; tj < k_NUM_ITERATIONS; ++tj) {
            const bool useZero = tj < k_NUM_USE_ZERO_ITERATIONS;
            const int numCorrectStrCodePoints = tj ? randUnsigned() % 4 + 2
                                                   : 0;

            correctStr.clear();
            for (int ii = 0; ii < numCorrectStrCodePoints; ++ii) {
                appendRandCorrectCodePoint(&correctStr, useZero);
            }

            if (veryVerbose) {
                P(dumpStr(correctStr));
            }

            for (int ti = 0; ti < NUM_DATA; ++ti) {
                const int   LINE         = DATA[ti].d_lineNum;
                const char *ERROR_STR    = DATA[ti].d_utf8_p;
                int         STATUS       = DATA[ti].d_numCodePoints;
                int         OFFSET       = DATA[ti].d_errOffset;

                if (0 <= STATUS) continue;

                Obj::ErrorStatus
                            ERROR_STATUS = static_cast<Obj::ErrorStatus>(
                                                                       STATUS);

                ASSERT(0 <= OFFSET);

                str = correctStr;
                bool zeroUsed = bsl::count(str.begin(), str.end(), '\0');
                ASSERT(!zeroUsed || useZero);

                errorStr.clear();
                if (EIT == ERROR_STATUS &&
                                30 <= intAbs(tj - k_NUM_USE_ZERO_ITERATIONS)) {
                    // In the end of buffer truncation cases, instead of taking
                    // 'ERROR_STR', manufacture a valid multibyte sequence of
                    // the same indicated length and then truncate it to the
                    // length of 'ERROR_STR'.

                    const IntPtr len = bsl::strlen(ERROR_STR + OFFSET);
                    const int    intendedLen = intendedSequenceLength(
                                                            ERROR_STR[OFFSET]);
                    ASSERT(len < intendedLen);
                    ASSERT(intendedLen - len <= 3);

                    errorStr.assign(ERROR_STR, OFFSET);
                    appendRandCorrectCodePoint(&errorStr, false, intendedLen);

                    errorStr.resize(OFFSET + len);
                }
                else if (SUR == ERROR_STATUS &&
                                30 <= intAbs(tj - k_NUM_USE_ZERO_ITERATIONS)) {
                    errorStr = BDLDE_UTF8UTIL_CASE_4::codeRandSurrogate();
                }
                else {
                    errorStr = ERROR_STR;
                }
                str += errorStr;

                ASSERT(str.length() < k_MAX_INPUT_LEN);

                const char * const begin       = str.c_str();
                const char * const endOfValid  = begin +
                                                  correctStr.length() + OFFSET;
                const char *       end;
                IntPtr             numCodePoints;
                int                sts;

                const IntPtr numOffsetCodePoints =
                                    Obj::numCodePointsIfValid(&end,
                                                              errorStr.c_str(),
                                                              OFFSET);
                ASSERT(0 <= numOffsetCodePoints);

                const IntPtr numCodePointsExp = numCorrectStrCodePoints +
                                                           numOffsetCodePoints;

                if (!zeroUsed) {
                    sts = -11;
                    end = "woof";
                    numCodePoints = Obj::advanceIfValid(&sts,
                                                        &end,
                                                        begin,
                                                        INT_PTR_MAX);
                    ASSERT(endOfValid == end);
                    ASSERT(numCodePointsExp == numCodePoints);
                    ASSERTV(LINE, ERROR_STATUS, sts, dumpStr(errorStr),
                                                          ERROR_STATUS == sts);

                    ASSERT(!Obj::isValid(begin));

                    end = "woof";
                    ASSERT(!Obj::isValid(&end, begin));
                    ASSERT(endOfValid == end);

                    end = "woof";
                    numCodePoints = Obj::numCodePointsIfValid(&end,
                                                              begin);
                    ASSERTV(end - endOfValid, ERROR_STATUS, endOfValid == end);
                    ASSERTV(LINE, ERROR_STATUS, numCodePoints,
                                                ERROR_STATUS == numCodePoints);
                }

                sts = -11;
                end = "woof";
                numCodePoints = Obj::advanceIfValid(&sts,
                                                    &end,
                                                    begin,
                                                    str.length(),
                                                    INT_PTR_MAX);
                ASSERT(endOfValid == end);
                ASSERT(numCodePointsExp == numCodePoints);
                ASSERTV(LINE, ERROR_STATUS, sts, ERROR_STATUS == sts);

                ASSERT(!Obj::isValid(begin, str.length()));

                end = "woof";
                ASSERT(!Obj::isValid(&end, begin, str.length()));
                ASSERT(endOfValid == end);

                end = "woof";
                numCodePoints = Obj::numCodePointsIfValid(&end,
                                                          begin,
                                                          str.length());
                ASSERT(endOfValid == end);
                ASSERTV(LINE, ERROR_STATUS, numCodePoints,
                                                ERROR_STATUS == numCodePoints);

                const IntPtr validLen  = endOfValid - begin;
                IntPtr       intStrLen = str.length();
                for (IntPtr endOutLen = intStrLen + 4,
                                   outLen = bsl::max<IntPtr>(4, intStrLen - 1);
                                           outLen <= endOutLen + 4; ++outLen) {
                    // Do the test twice, with and without the seek check,
                    // since that seek might throw off the behavior after it.

                    for (int tk = 0; tk < 2; ++tk) {
                        bool CHECK_WITH_SEEK = tk;

                        fsb.pubsetbuf(begin, str.length());
                        out.resize(0);
                        out.resize(outLen + 1, badChar);

                        IntPtr intBufLen = Obj::readIfValid(&sts,
                                                            &out[0],
                                                            outLen,
                                                            &fsb);
                        ASSERT(0 <= intBufLen);

                        ASSERTV(dumpStr(str), intBufLen, outLen,
                                                          intBufLen <= outLen);
                        ASSERTV(dumpStr(str), intBufLen, outLen,
                                                        intBufLen <= validLen);
                        ASSERT(badChar == out[outLen]);

                        if (sts == ERROR_STATUS) {
                            ASSERT(intBufLen == validLen);
                            ASSERT(0 == validLen || 0 < intBufLen);
                        }
                        else {
                            ASSERTV(sts, ERROR_STATUS, 0 < sts);
                            ASSERTV(outLen, intStrLen,
                                                      outLen - 3 <= intStrLen);
                        }

                        out.resize(intBufLen);
                        ASSERTV(dumpStr(out),
                                             Obj::isValid(&out[0], intBufLen));

                        if (CHECK_WITH_SEEK) {
                            ASSERT(fsb.pubseekoff(0, bsl::ios_base::cur,
                                  bsl::ios_base::in) ==
                                          bsl::streambuf::pos_type(intBufLen));
                        }

                        bsl::string remainderStr;
                        remainderStr.resize(1024);
                        const IntPtr expLen = str.length() - intBufLen;
                        ASSERT(expLen == fsb.sgetn(&remainderStr[0], 1024));
                        remainderStr.resize(expLen);
                        ASSERTV(dumpStr(str.substr(intBufLen)),
                                                         dumpStr(remainderStr),
                                        str.substr(intBufLen) == remainderStr);
                    }
                }

                // Now, we tack a correct char on after and observe no change
                // to the result:

                for (unsigned uu = randUnsigned() % 3 + 1; 0 < uu--; ) {
                    appendRandCorrectCodePoint(&str, useZero);
                }
                zeroUsed = zeroUsed || (useZero &&
                                     bsl::count(str.begin(), str.end(), '\0'));

                ERROR_STATUS = EIT == ERROR_STATUS ? NCO : ERROR_STATUS;

                if (!zeroUsed) {
                    ASSERT(bsl::strlen(begin) == str.length());

                    sts = -11;
                    end = "woof";
                    numCodePoints = Obj::advanceIfValid(&sts,
                                                        &end,
                                                        begin,
                                                        INT_PTR_MAX);
                    ASSERT(endOfValid == end);
                    ASSERT(numCodePointsExp == numCodePoints);
                    ASSERT(ERROR_STATUS == sts);

                    ASSERT(!Obj::isValid(begin));

                    end = "woof";
                    ASSERT(!Obj::isValid(&end, begin));
                    ASSERT(endOfValid == end);

                    end = "woof";
                    numCodePoints = Obj::numCodePointsIfValid(&end,
                                                              begin);
                    ASSERT(endOfValid == end);
                    ASSERT(ERROR_STATUS == numCodePoints);
                }

                sts = -11;
                end = "woof";
                numCodePoints = Obj::advanceIfValid(&sts,
                                                    &end,
                                                    begin,
                                                    str.length(),
                                                    INT_PTR_MAX);
                ASSERT(endOfValid == end);
                ASSERT(numCodePointsExp == numCodePoints);
                ASSERTV(LINE, ERROR_STATUS, sts,
                                     str[str.length()-1], ERROR_STATUS == sts);

                ASSERT(!Obj::isValid(begin, str.length()));

                end = "woof";
                ASSERT(!Obj::isValid(&end, begin, str.length()));
                ASSERT(endOfValid == end);

                end = "woof";
                numCodePoints = Obj::numCodePointsIfValid(&end,
                                                          begin,
                                                          str.length());
                ASSERT(endOfValid == end);
                ASSERTV(LINE, dumpStr(errorStr), ERROR_STATUS, numCodePoints,
                                                ERROR_STATUS == numCodePoints);

                intStrLen = str.length();
                for (IntPtr endOutLen = intStrLen + 4,
                                   outLen = bsl::max<IntPtr>(4, intStrLen - 1);
                                           outLen <= endOutLen + 4; ++outLen) {
                    // Do the test twice, with and without the seek check,
                    // since that seek might throw off the behavior after it.

                    for (int tk = 0; tk < 2; ++tk) {
                        bool CHECK_WITH_SEEK = tk;

                        fsb.pubsetbuf(begin, str.length());
                        out.resize(0);
                        out.resize(outLen + 1, badChar);

                        IntPtr intBufLen = Obj::readIfValid(&sts,
                                                            &out[0],
                                                            outLen,
                                                            &fsb);
                        ASSERT(0 <= intBufLen);
                        ASSERT(badChar == out[outLen]);

                        ASSERTV(dumpStr(str), intBufLen, outLen,
                                                          intBufLen <= outLen);
                        ASSERTV(dumpStr(str), intBufLen, outLen,
                                                        intBufLen <= validLen);

                        if (sts == ERROR_STATUS) {
                            ASSERT(intBufLen == validLen);
                            ASSERT(0 == validLen || 0 < intBufLen);
                        }
                        else {
                            ASSERTV(sts, ERROR_STATUS, 0 < sts);
                            ASSERTV(outLen, intStrLen,
                                                      outLen - 3 <= intStrLen);
                        }

                        out.resize(intBufLen);
                        ASSERTV(dumpStr(out), Obj::isValid(&out[0],
                                                                   intBufLen));

                        if (CHECK_WITH_SEEK) {
                            ASSERT(fsb.pubseekoff(0, bsl::ios_base::cur,
                                  bsl::ios_base::in) ==
                                          bsl::streambuf::pos_type(intBufLen));
                        }
                        bsl::string remainderStr;
                        remainderStr.resize(1024);
                        const IntPtr expLen = str.length() - intBufLen;
                        ASSERT(expLen == fsb.sgetn(&remainderStr[0], 1024));
                        remainderStr.resize(expLen);
                        ASSERTV(dumpStr(str.substr(intBufLen)),
                                                         dumpStr(remainderStr),
                                        str.substr(intBufLen) == remainderStr);
                    }
                }
            }
        }
      } break;
      case 8: {
        // --------------------------------------------------------------------
        // TESTING EXHAUSTIVE CORRECT SEQUENCES
        //
        // CONCERN:
        //: 1 That 'advanceIfValid' and 'advanceRaw' perform as documented on
        //:   computer-generated sequences of correct UTF-8 input.
        //
        // PLAN:
        //: 1 We create static functions 'appendRand*Char(bsl::string*)' that
        //:   will append one random Unicode code point of the 4 possible valid
        //:   lengths to a string.
        //:
        //: 2 There are 5 types of code points we will have in the input
        //:   strings: non-zero Unicode values of the 4 possible lengths, and
        //:   the zero char.  We represent string containing up to two of each
        //:   of those values with a vector 'vec' of integers, where value
        //:   '1-4' represent non-zero Unicode code points of the length
        //:   indicated by the number, and 0 representing a 0 code point.
        //:
        //: 3 We do our tests twice, once where we don't include any 0 code
        //:   points for testing functions that take zero-terminated input, and
        //:   again including 0 code points, by iterating on 'useZero',
        //:   effectively a boolean.
        //:
        //: 4 We have an integer key, where the bottom several bits of the
        //:   value indicate whether Unicode code points of a given length will
        //:   be present in the value.  The key is 8 bits long if 0 is not
        //:   used, 10 bits long if 0 is used (two bits for each length, to
        //:   indicate the presence or absence of up to 2 instances of Unicode
        //:   code points).
        //:
        //: 5 The key is processed into 'vec', where each element of vec
        //:   indicates the Unicode code point length (or 0 value) of a Unicode
        //:   code point to be present in the test string.
        //:
        //: 6 We then iterate through all permutations of 'vec'.
        //:
        //: 7 For each permutation, we translate 'vec' into a string, using the
        //:   'appendRaw*Char' functions described above.
        //:
        //: 8 We then call all forms of 'advance*' function on this string, and
        //:   observe that the return values are as expected.
        //:
        //: 9 We then call 'readValidUtf8ToBuffer' on the input with a variety
        //:    of output buffer lengths.
        //:
        //: 10 We then push a random garbage char onto the end of the string.
        //:   Since we 'reserve'd a long length for the string, this will not
        //:   cause a reallocation of the buffer or invalidation of any of our
        //:   pointers at or into the string.
        //:
        //: 11 We then call the 'advance' functions that either don't take 0
        //:    terminated input, or that are passed 'numCodePoints', which will
        //:    tell the 'advance*' to finish before examining the garbage byte,
        //:    and observe the functions succeed.
        //
        // Testing:
        //   IntPtr advanceIfValid(int *, const char **, const char *, int);
        //   IntPtr advanceIfValid(int *, const char **, const char *,int,int);
        //   IntPtr advanceRaw(const char **, const char *, int);
        //   IntPtr advanceRaw(const char **, const char *, int, int);
        //   bool isValid(const char *);
        //   bool isValid(const char *, int);
        //   bool isValid(const char **, const char *);
        //   bool isValid(const char **, const char *, int);
        //   IntPtr numCodePointsIfValid(const char **, const char *);
        //   IntPtr numCodePointsIfValid(const char **, const char *, int);
        //   size_t readIfValid(int *, char *, size_t, streambuf *);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING EXHAUSTIVE CORRECT SEQUENCES\n"
                               "====================================\n";

        bsl::string str, out;

        const IntPtr INT_PTR_MAX = ~static_cast<bsl::size_t>(0) >> 1;

        enum { k_NUM_ITERATIONS          = 70 * 1000,
               k_NUM_USE_ZERO_ITERATIONS = k_NUM_ITERATIONS / 10,
               k_MAX_INPUT_LEN           = 200 };

        str.reserve(k_MAX_INPUT_LEN);   // reserve longer than the longest
                                        // length we will use, so no
                                        // manipulation of this 'string' will
                                        // result in a reallocation and a move
                                        // of the buffer.
        out.reserve(k_MAX_INPUT_LEN + 4);

        const char *WOOF = "woof";

        for (int tj = 0; tj < k_NUM_ITERATIONS; ++tj) {
            const bool useZero = tj < k_NUM_USE_ZERO_ITERATIONS;
            const int  numCodePointsExp = randUnsigned() % 6 + 4;

            str.clear();
            for (int ii = 0; ii < numCodePointsExp; ++ii) {
                appendRandCorrectCodePoint(&str, useZero);
            }
            ASSERT(str.length() < k_MAX_INPUT_LEN);

            if (veryVeryVerbose ||
                               (intAbs(tj - k_NUM_USE_ZERO_ITERATIONS) < 100 &&
                                                                veryVerbose)) {
                P(dumpStr(str));
            }

            const bool zeroUsed = bsl::count(str.begin(), str.end(), '\0');
            ASSERT(!zeroUsed || useZero);

            const char * const begin       = str.c_str();
            const char * const endOfString = &*str.end();
            const char *       end;
            IntPtr             numCodePoints;
            int                sts;
            const bsl::size_t  strLength = str.length();

            if (!zeroUsed) {
                end = WOOF;
                numCodePoints = Obj::advanceRaw(&end, begin, INT_MAX);
                ASSERT(endOfString == end);
                ASSERT(numCodePointsExp == numCodePoints);

                sts = -11;
                end = WOOF;
                numCodePoints = Obj::advanceIfValid(&sts,
                                                    &end,
                                                    begin,
                                                    INT_PTR_MAX);
                ASSERT(endOfString == end);
                ASSERT(numCodePointsExp == numCodePoints);
                ASSERT(0 == sts);

                ASSERT(Obj::isValid(begin));

                end = WOOF;
                ASSERT(Obj::isValid(&end, begin));
                ASSERT(WOOF == end);

                end = WOOF;
                numCodePoints = Obj::numCodePointsIfValid(&end,
                                                          begin);
                ASSERT(WOOF == end);
                ASSERT(numCodePointsExp == numCodePoints);

                numCodePoints = Obj::numCodePointsRaw(begin);
                ASSERT(numCodePointsExp == numCodePoints);
            }

            end = "woof";
            numCodePoints = Obj::advanceRaw(&end,
                                            begin,
                                            strLength,
                                            INT_PTR_MAX);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);

            sts = -11;
            end = "woof";
            numCodePoints = Obj::advanceIfValid(&sts,
                                                &end,
                                                begin,
                                                strLength,
                                                INT_PTR_MAX);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);
            ASSERT(0 == sts);

            ASSERT(Obj::isValid(begin, strLength));

            end = WOOF;
            ASSERT(Obj::isValid(&end, begin, strLength));
            ASSERT(WOOF == end);

            end = WOOF;
            numCodePoints = Obj::numCodePointsIfValid(&end,
                                                      begin,
                                                      strLength);
            ASSERT(WOOF == end);
            ASSERT(numCodePointsExp == numCodePoints);

            numCodePoints = Obj::numCodePointsRaw(begin, strLength);
            ASSERT(numCodePointsExp == numCodePoints);

            bdlsb::FixedMemInStreamBuf fsb(0, 0);

            const char badChar = static_cast<char>(0xf8);     // 'f8' is ALWAYS
                                                              // illegal UTF-8
            IntPtr sbLen0 = bsl::max<IntPtr>(strLength - 3, 0);
            const IntPtr sbEnd = strLength;
            static bool firstTime = true;
            if (firstTime) {
                firstTime = false;

                // We want to try with an empty streambuf, but only once

                sbLen0 = 0;
            }
            for (IntPtr sbLen = sbLen0; sbLen <= sbEnd;
                                      sbLen = bsl::max(sbLen + 1, sbEnd - 3)) {
                for (IntPtr outLen = 4; outLen <= sbLen + 4;
                                    outLen = bsl::max(outLen + 1, sbLen - 3)) {
                    ASSERT(outLen <= k_MAX_INPUT_LEN + 4);

                    out.resize(0);
                    out.resize(outLen, badChar);

                    fsb.pubsetbuf(begin, sbLen);

                    const bool inputValid = Obj::isValid(begin, sbLen);

                    IntPtr intBufLen = Obj::readIfValid(&sts,
                                                        &out[0],
                                                        outLen,
                                                        &fsb);
                    ASSERT(0 <= intBufLen);

                    switch (sts) {
                      case 0: {
                        ASSERT(intBufLen == sbLen);
                      } break;
                      case Obj::k_END_OF_INPUT_TRUNCATION: {
                        ASSERT(!inputValid);
                        IntPtr ii = 1, end = bsl::min<IntPtr>(3, sbLen);
                        for (; ii <= end; ++ii) {
                            if ((0xc0 & begin[sbLen - ii]) == 0xc0) {
                                break;
                            }
                        }
                        ASSERT(ii <= end);
                      } break;
                      default: {
                        if (0 < sts) {
                            ASSERT(outLen <= sbLen + 3);
                        }
                        else {
                            ASSERTV(sts, 0 && "unexpected error");
                        }
                      }
                    }

                    ASSERTV(intBufLen, outLen, intBufLen <= outLen);
                    ASSERTV(intBufLen, sbLen,  intBufLen <= sbLen);
                    ASSERTV(intBufLen, sbLen, outLen,
                                   bsl::min(sbLen, outLen-3) - intBufLen <= 3);
                    ASSERTV(0 < intBufLen || 0 == sbLen ||
                                                   (!inputValid && sbLen < 4));

                    ASSERT(0 == bsl::memcmp(&out[0], begin,intBufLen));
                    ASSERT(Obj::isValid(&out[0], intBufLen));

                    if (inputValid) {
                        ASSERT(0 <= sts);
                        ASSERT((0 < sts) ==
                                       (outLen - 4 < static_cast<int>(sbLen)));

                        if (4 == outLen && 0 < sbLen) {
                            end = WOOF;
                            ASSERT(1 == Obj::numCodePointsIfValid(&end,
                                                                  &out[0],
                                                                  intBufLen));
                            ASSERT(WOOF == end);
                        }
                    }
                    else {
                        ASSERT(0 != sts);
                        ASSERTV(sts, sbLen + 3 > outLen ||
                                        Obj::k_END_OF_INPUT_TRUNCATION == sts);
                    }
                }
            }

            // Now we tack an extra non-zero garbage char on the end 'str', and
            // make sure that it makes no difference when when 'strLength' and
            // 'numCodePointsExp' dictate that it will not be read.

            // Don't use 'c == 0' as we already tested that above.

            char c = char(randUnsigned() % 256 - 128);
            c = c ? c : 'a';
            str.push_back(c);

            end = "woof";
            numCodePoints = Obj::advanceRaw(&end,
                                            begin,
                                            strLength,
                                            INT_PTR_MAX);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);

            sts = -11;
            end = "woof";
            numCodePoints = Obj::advanceIfValid(&sts,
                                           &end,
                                           begin,
                                           strLength,
                                           INT_PTR_MAX);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);
            ASSERT(0 == sts);

            if (!zeroUsed) {
                end = "woof";
                numCodePoints = Obj::advanceRaw(&end,
                                                begin,
                                                numCodePointsExp);
                ASSERT(endOfString == end);
                ASSERT(numCodePointsExp == numCodePoints);

                sts = -11;
                end = "woof";
                numCodePoints = Obj::advanceIfValid(&sts,
                                                    &end,
                                                    begin,
                                                    numCodePointsExp);
                ASSERT(endOfString == end);
                ASSERT(numCodePointsExp == numCodePoints);
                ASSERT(0 == sts);
            }

            end = "woof";
            numCodePoints = Obj::advanceRaw(&end,
                                            begin,
                                            strLength + 1,
                                            numCodePointsExp);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);

            sts = -11;
            end = "woof";
            numCodePoints = Obj::advanceIfValid(&sts,
                                                &end,
                                                begin,
                                                strLength + 1,
                                                numCodePointsExp);
            ASSERT(endOfString == end);
            ASSERT(numCodePointsExp == numCodePoints);
            ASSERT(0 == sts);

            ASSERT(Obj::isValid(begin, strLength));

            end = WOOF;
            ASSERT(Obj::isValid(&end, begin, strLength));
            ASSERT(WOOF == end);

            end = WOOF;
            numCodePoints = Obj::numCodePointsIfValid(&end,
                                                      begin,
                                                      strLength);
            ASSERT(WOOF == end);
            ASSERT(numCodePointsExp == numCodePoints);

            numCodePoints = Obj::numCodePointsRaw(begin, strLength);
            ASSERT(numCodePointsExp == numCodePoints);
        }
      } break;
      case 7: {
        // --------------------------------------------------------------------
        // TESTING REAL PROSE
        //
        // Concerns:
        //: 1 That 'advanceIfValid' and 'advanceRaw', in both their forms, can
        //:   handle a long sequence of correct UTF-8.
        //
        // Plan:
        //: 1 Run both forms of 'advanceIfValid' and 'advanceRaw', respectively
        //:   on our string 'charUtf8MultiLang', and observe that they count
        //:   the code points correctly, and don't report any errors.
        //
        // Testing:
        //   IntPtr advanceIfValid(int *, const char **, const char *, int);
        //   IntPtr advanceIfValid(int*,const char**,const char *,int,int);
        //   IntPtr advanceRaw(const char **, const char *, int);
        //   IntPtr advanceRaw(const char **, const char *, int, int);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING REAL PROSE\n"
                               "==================\n";

        const char *result;
        IntPtr      numCodePoints;
        int         sts;

        const char * const begin  = charUtf8MultiLang;
        bsl::size_t        length = sizeof(utf8MultiLang) - 1;
        const char * const end    = begin + length;

        const int expectedNumCPs = NUM_UTF8_MULTI_LANG_CODE_POINTS - 1;

        sts      = -2;
        result   = "woof";
        numCodePoints = Obj::advanceIfValid(&sts, &result, begin, INT_MAX);
        ASSERT(expectedNumCPs == numCodePoints);
        ASSERT(result == end);
        ASSERT(0 == sts);

        sts      = -2;
        result   = "woof";
        numCodePoints = Obj::advanceIfValid(&sts,
                                            &result,
                                            begin,
                                            length,
                                            INT_MAX);
        ASSERT(NUM_UTF8_MULTI_LANG_CODE_POINTS - 1 == numCodePoints);
        ASSERT(result == end);
        ASSERT(0 == sts);

        sts      = -2;
        result   = "woof";
        numCodePoints = Obj::advanceIfValid(&sts,
                                            &result,
                                            begin,
                                            length + 1,
                                            expectedNumCPs);
        ASSERT(expectedNumCPs == numCodePoints);
        ASSERT(result == end);
        ASSERT(0 == sts);

        sts      = -2;
        result   = "woof";
        numCodePoints = Obj::advanceIfValid(&sts,
                                            &result,
                                            begin,
                                            0,
                                            expectedNumCPs);
        ASSERT(0 == numCodePoints);
        ASSERT(0 == sts);
        ASSERT(result == begin);

        result   = "woof";
        numCodePoints = Obj::advanceRaw(&result, begin, INT_MAX);
        ASSERT(expectedNumCPs == numCodePoints);
        ASSERT(result == end);

        result   = "woof";
        numCodePoints = Obj::advanceRaw(&result, begin, length, INT_MAX);
        ASSERT(NUM_UTF8_MULTI_LANG_CODE_POINTS - 1 == numCodePoints);
        ASSERT(result == end);

        result   = "woof";
        numCodePoints = Obj::advanceRaw(&result,
                                        begin,
                                        length + 1,
                                        expectedNumCPs);
        ASSERT(expectedNumCPs == numCodePoints);
        ASSERT(result == end);

        result   = "woof";
        numCodePoints = Obj::advanceRaw(&result,
                                        begin,
                                        0,
                                        expectedNumCPs);
        ASSERT(0 == numCodePoints);
        ASSERT(result == begin);
      } break;
      case 6: {
        // --------------------------------------------------------------------
        // TESTING 'isValid' & 'numCodePointsIfValid'
        //
        // Concerns:
        //: 1 The methods under test produce the expected results on both
        //:   valid and invalid UTF-8 strings.
        //
        // Plan:
        //: 1 Use the table-driven approach to verify correct behavior on
        //:   various valid and invalid UTF-8 strings.
        //
        // Testing:
        //   bool isValid(const char *s);
        //   bool isValid(const char *s, int len);
        //   bool isValid(const char **err, const char *s);
        //   bool isValid(const char **err, const char *s, int len);
        //   IntPtr numCharactersIfValid(**err, const char *s);
        //   IntPtr numCharactersIfValid(**err, const char *s, int len);
        //   IntPtr numCodePointsIfValid(**err, const char *s);
        //   IntPtr numCodePointsIfValid(**err, const char *s, int len);
        // --------------------------------------------------------------------

        if (verbose) cout << "\nTESTING 'isValid' & 'numCodePointsIfValid'\n"
                               "==========================================\n";

        IntPtr rc;

        for (int ti = 0; ti < NUM_DATA; ++ti) {
            const int   LINE     = DATA[ti].d_lineNum;
            const char *UTF8     = DATA[ti].d_utf8_p;
            const int   NUMBYTES = DATA[ti].d_numBytes;
            const int   NUMCPS   = DATA[ti].d_numCodePoints;
            const int   ERROFF   = DATA[ti].d_errOffset;
            const bool  VALID    = DATA[ti].d_isValid;

            if (veryVerbose) {
                T_; P_(ti);
                P_(UTF8); P_(NUMBYTES); P_(NUMCPS); P_(ERROFF); P(VALID);
            }

            ASSERTV(LINE, static_cast<int>(bsl::strlen(UTF8)) == NUMBYTES);

            LOOP_ASSERT(LINE, VALID == Obj::isValid(UTF8));
            LOOP_ASSERT(LINE, VALID == Obj::isValid(UTF8, NUMBYTES));
            LOOP_ASSERT(LINE, VALID == Obj::isValid(UTF8, NUMBYTES + 1));

            const char *ERRSTR = 0;

            ERRSTR = 0;
            LOOP_ASSERT(LINE, VALID == Obj::isValid(&ERRSTR, UTF8));

            if (VALID) {
                LOOP_ASSERT(LINE, 0      == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }

            ERRSTR = 0;
            LOOP_ASSERT(LINE, VALID == Obj::isValid(&ERRSTR, UTF8, NUMBYTES));

            if (VALID) {
                LOOP_ASSERT(LINE, 0      == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }

            ERRSTR = 0;
            LOOP_ASSERT(LINE, VALID == Obj::isValid(&ERRSTR,
                                                    UTF8,
                                                    NUMBYTES + 1));

            if (VALID) {
                LOOP_ASSERT(LINE, 0      == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }

            ERRSTR = 0;
            rc = Obj::numCharactersIfValid(&ERRSTR, UTF8);
            ASSERTV(LINE, NUMCPS, rc, NUMCPS == rc);

            ERRSTR = 0;
            LOOP_ASSERT(LINE, NUMCPS == Obj::numCodePointsIfValid(&ERRSTR,
                                                                  UTF8));

            if (VALID) {
                LOOP_ASSERT(LINE, 0      == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }

            ERRSTR = 0;
            LOOP_ASSERT(LINE, NUMCPS == Obj::numCharactersIfValid(&ERRSTR,
                                                                    UTF8,
                                                                    NUMBYTES));

            ERRSTR = 0;
            ASSERTV(LINE, NUMCPS, rc,
                         NUMCPS == (rc = Obj::numCodePointsIfValid(&ERRSTR,
                                                                   UTF8,
                                                                   NUMBYTES)));

            if (VALID) {
                LOOP_ASSERT(LINE, 0      == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }

            ERRSTR = 0;
            if (VALID) {
                LOOP_ASSERT(LINE, NUMCPS + 1 ==
                                      Obj::numCharactersIfValid(&ERRSTR,
                                                                UTF8,
                                                                NUMBYTES + 1));
                LOOP_ASSERT(LINE, NUMCPS + 1 ==
                                      Obj::numCodePointsIfValid(&ERRSTR,
                                                                UTF8,
                                                                NUMBYTES + 1));
                LOOP_ASSERT(LINE, 0 == ERRSTR);
            }
            else {
                LOOP_ASSERT(LINE, Obj::numCharactersIfValid(&ERRSTR,
                                                            UTF8,
                                                            NUMBYTES + 1) < 0);
                LOOP_ASSERT(LINE, Obj::numCodePointsIfValid(&ERRSTR,
                                                            UTF8,
                                                            NUMBYTES + 1) < 0);
                LOOP_ASSERT(LINE, ERROFF == ERRSTR - UTF8);
            }
        }

      } break;
      case 5: {
        // --------------------------------------------------------------------
        // TESTING 'numCharactersRaw'
        //
        // Concerns:
        //: 1 The methods under test produce the expected results on both
        //:   valid and invalid UTF-8 strings.
        //
        // Plan:
        //: 1 Use the table-driven approach to verify correct behavior on
        //:   various valid and invalid UTF-8 strings.
        //
        // Testing:
        //   IntPtr numCharacters(const char *s);
        //   IntPtr numCharacters(const char *s, int len);
        //   IntPtr numCharactersRaw(const char *s);
        //   IntPtr numCharactersRaw(const char *s, int len);
        //   IntPtr numCodePointsRaw(const char *s);
        //   IntPtr numCodePointsRaw(const char *s, int len);
        //   IntPtr numCharacters(const char *s);
        //   IntPtr numCharacters(const char *s, int len);
        // --------------------------------------------------------------------

        if (verbose) cout << "TESTING 'numCharactersRaw'" << endl
                          << "==========================" << endl;

        for (int ti = 0; ti < NUM_DATA; ++ti) {
            const int   LINE     = DATA[ti].d_lineNum;
            const char *UTF8     = DATA[ti].d_utf8_p;
            const int   NUMBYTES = DATA[ti].d_numBytes;
            const int   NUMCPS   = DATA[ti].d_numCodePoints;
            const int   VALID    = DATA[ti].d_isValid;

            if (!VALID) continue;

            if (veryVerbose) {
                T_; P_(ti); P_(UTF8); P_(NUMBYTES); P_(NUMCPS); P(VALID);
            }

            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCodePointsRaw(UTF8));

            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCodePointsRaw(UTF8,
                                                            NUMBYTES));
            LOOP_ASSERT(LINE,
                        NUMCPS + 1 == Obj::numCodePointsRaw(UTF8,
                                                            NUMBYTES + 1));

            // DEPRECATED
            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCharactersRaw(UTF8));

            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCharactersRaw(UTF8,
                                                            NUMBYTES));
            LOOP_ASSERT(LINE,
                        NUMCPS + 1 == Obj::numCharactersRaw(UTF8,
                                                            NUMBYTES + 1));

            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCharacters(UTF8));

            LOOP_ASSERT(LINE,
                        NUMCPS     == Obj::numCharacters(UTF8, NUMBYTES));
            LOOP_ASSERT(LINE,
                        NUMCPS + 1 == Obj::numCharacters(UTF8,
                                                         NUMBYTES + 1));
        }

      } break;
      case 4: {
        // --------------------------------------------------------------------
        // TESTING SURROGATES
        //
        // Surrogates are special values encoded in pairs in UTF-16 to encode
        // high Unicode values.  It is mathematically impossible to encode a
        // surrogate value, alone or as a pair, in UTF-16.  It is
        // mathematically possible to encode them in UTF-8, but we make them
        // artificially illegal so that any valid UTF-8 sequence can be
        // translated to UTF-16.
        //
        // Concerns:
        //: 1 Create some strings containing surrogate pairs and verify that
        //:   the validation routines interpret them properly.
        //
        // Plan:
        //: 1 Create a large number of strings containing valid and invalid
        //:   surrogates and verify that the validation routines handle them
        //:   properly.
        //
        // Testing:
        //   bool isValid(const char *s);
        //   bool isValid(const char *s, int len);
        //   bool isValid(const char **err, const char *s);
        //   bool isValid(const char **err, const char *s, int len);
        //   IntPtr advanceIfValid(int *, const char **, const char *, int);
        //   IntPtr advanceIfValid(int*,const char**,const char *,int,int);
        //   IntPtr numCodePointsIfValid(**err, const char *s);
        //   IntPtr numCodePointsIfValid(**err, const char *s, int len);
        // --------------------------------------------------------------------

        if (verbose) cout << "TESTING SURROGATES" << endl
                          << "==================" << endl;

        using namespace BDLDE_UTF8UTIL_CASE_4;

        bsl::string str;
        str.reserve(6 * 4 + 6 + 1);

        randAccum = 0;

        // test strings with surrogate pairs
        for (int i = 5000; i > 0; -- i) {
            const int rv = randVal();
            const int numLeading = rv & 3;
            const int numTrailing = (rv >> 2) & 3;
            str = "";
            for (int j = 0; j < numLeading; ++ j) {
                str += codeRandBenign();
            }
            const IntPtr preLen = str.length();
            str += codeRandSurrogatePair();
            for (int j = 0; j < numTrailing; ++ j) {
                str += codeRandBenign();
            }

            ASSERT(false == allValid(str));

            int sts;
            const char *invalidPoint;
            ASSERT(numLeading == allAdvanceIfValid(&sts, &invalidPoint, str));
            ASSERT(Obj::k_SURROGATE == sts);
            ASSERT(str.c_str() + preLen == invalidPoint);

            invalidPoint = 0;
            ASSERT(Obj::k_SURROGATE == allNumCodePointsIfValid(&invalidPoint,
                                                               str));
            ASSERT(str.c_str() + preLen == invalidPoint);
        }

        randAccum = 0;

        // test strings with lone surrogates
        for (int i = 5000; i > 0; -- i) {
            int rv = randVal();
            int numLeading = rv & 3;
            int numTrailing = (rv >> 2) & 3;
            str = "";
            for (int j = 0; j < numLeading; ++ j) {
                str += codeRandBenign();
            }
            const IntPtr preLen = str.length();
            str += codeRandSurrogate();
            for (int j = 0; j < numTrailing; ++ j) {
                str += codeRandBenign();
            }

            ASSERT(false == allValid(str));

            int sts;
            const char *invalidPoint;
            ASSERT(numLeading == allAdvanceIfValid(&sts, &invalidPoint, str));
            ASSERT(Obj::k_SURROGATE == sts);
            ASSERT(str.c_str() + preLen == invalidPoint);

            invalidPoint = 0;
            ASSERT(Obj::k_SURROGATE == allNumCodePointsIfValid(&invalidPoint,
                                                               str));
            ASSERT(str.c_str() + preLen == invalidPoint);
        }
      } break;
      case 3: {
        // --------------------------------------------------------------------
        // TESTING BYTE-ORDER MARK
        //
        // Concerns:
        //: 1 Verify byte-order mark is accepted by all the validation
        //:   routines.
        //
        // Plan:
        //: 1 Create a byte-order mark and feed it to the validation routines,
        //:   it should always be acceptable.  Also create UTF-16 BOM's of both
        //:   byte orders, they should be rejected.
        //
        // Testing:
        //   bool isValid(const char *s);
        //   bool isValid(const char *s, int len);
        //   bool isValid(const char **err, const char *s);
        //   bool isValid(const char **err, const char *s, int len);
        // --------------------------------------------------------------------

        if (verbose) cout << "TESTING BYTE-ORDER MARK" << endl
                          << "=======================" << endl;

        using namespace BDLDE_UTF8UTIL_CASE_2;

        typedef const char Char;

        Char c    = char(0x80);    // 'c'ontinuation
        Char b3   = char(0xe0);    // 'b'eginning of 3-byte
        Char b4   = char(0xf0);    // 'b'eginning of 4-byte

        Char encode4a[] = { b4, char(c | 0x10), c, c };    // 0x10000

        bsl::string s4a = STR(4a);

        bsl::string s1b = code8(47);
        ASSERT(1 == s1b.length());

        ASSERT(allValid(s4a));

        unsigned char uBom[] = { 0xef, 0xbb, 0xbf };
        Char          bom[]  = { b3 | 0xf, c | 0x3b, c | 0x3f };

        const int     bomVal = (0xf << 12) + (0x3b << 6) + 0x3f;

        ASSERT(0 == bsl::memcmp(uBom, bom, 3));

        bsl::string sBom = makeString(bom, sizeof(bom));
        ASSERT(codeBOM() == sBom);
        ASSERT(code24(bomVal) == sBom);

        const char *pc = bom;
        ASSERT(bomVal == decode(&pc));
        ASSERT(bom + sizeof(bom) == pc);

        ASSERT(allValid(sBom));

        bsl::string lStr = sBom + s4a + s4a;

        ASSERT(allValid(lStr));

        lStr = s4a + s4a + sBom + s4a + s4a;

        ASSERT(allValid(lStr));

        lStr = s4a + s4a + sBom;

        ASSERT(allValid(lStr));

        lStr = s4a + s4a + sBom + s1b;

        ASSERT(allValid(lStr));

        Char encode16BomLe[] = { char(0xff), char(0xfe) };
        Char encode16BomBe[] = { char(0xfe), char(0xff) };

        bsl::string bomLe = STR(16BomLe);
        bsl::string bomBe = STR(16BomBe);

        ASSERT(! allValid(bomLe));
        ASSERT(! allValid(bomBe));

        lStr = s4a + bomLe;
        ASSERT(! allValid(lStr));

        lStr = s4a + bomBe;
        ASSERT(! allValid(lStr));

        lStr = s4a + bomLe + s4a;
        ASSERT(! allValid(lStr));

        lStr = s4a + bomBe + s4a;
        ASSERT(! allValid(lStr));

        lStr = s4a + bomLe + s1b;
        ASSERT(! allValid(lStr));

        lStr = s4a + bomBe + s1b;
        ASSERT(! allValid(lStr));
      } break;
      case 2: {
        // --------------------------------------------------------------------
        // TABLE-DRIVEN ENCODING / DECODING / VALIDATION TEST
        //
        // Concerns:
        //: 1 Test encoding, decoding, and validation on data that is table
        //:   driven rather than randomly generated.
        //
        // Plan:
        //: 1 Encode some const char strings with specific values, try encoding
        //:   them and verify the expected results are yields.  Run the
        //:   validation routines on them and verify the expected results.
        //:   Code various forms of invalid strings and observe that the
        //:   validators reject them appropriately.  Several types of encodings
        //:   are represented.  UTF-8 zero, Modified UTF-8 zero, many values
        //:   that are valid in both UTF-8 and modified UTF-8, overlong values
        //:   other than zero, blatantly invalid values, and short values.
        //
        // Testing:
        //   TABLE-DRIVEN ENCODING / DECODING / VALIDATION TEST
        // --------------------------------------------------------------------

        if (verbose) cout <<
                      "\nTABLE-DRIVEN ENCODING / DECODING / VALIDATION TEST\n"
                        "==================================================\n";

        using namespace BDLDE_UTF8UTIL_CASE_2;

        typedef const char Char;

        Char c    = char(0x80);    // 'c'ontinuation
        Char b2   = char(0xc0);    // 'b'eginning of 2-byte
        Char b3   = char(0xe0);    // 'b'eginning of 3-byte
        Char b4   = char(0xf0);    // 'b'eginning of 4-byte
        Char b5   = char(0xf8);    // 'b'eginning of 5-byte
        Char b6   = char(0xfc);    // 'b'eginning of 6-byte
        Char b7   = char(0xfe);    // 'b'eginning of 6-byte

        Char encode1a[] = { 0 };                        int val1a = 0;
        Char encode1b[] = { 0x35 };                     int val1b = 0x35;
        Char encode1c[] = { 0x47 };                     int val1c = 0x47;
        Char encode1d[] = { 0x63 };                     int val1d = 0x63;
        Char encode1e[] = { 0x7f };                     int val1e = 0x7f;

        Char encode2a[] = { b2 | 2, c };                int val2a = 0x80;
        Char encode2b[] = { b2 | 3, c | 3 };            int val2b = 3*64 + 3;
        Char encode2c[] = { b2 | 0xf, c | 0xf };        int val2c = 15*64 + 15;
        Char encode2d[] = { b2 | 0x10, c | 7 };         int val2d = 16*64 + 7;
        Char encode2e[] = { b2 | 0x1f, c | 0x3f };      int val2e = 0x7ff;

        Char encode3a[] = { b3, c | 0x20, c | 0 };      int val3a = 0x800;
        Char encode3b[] = { b3, c | 58, c | 0 };        int val3b = 58 * 64;
        Char encode3c[] = { b3, c | 0x3f, c | 0x3f };   int val3c = 0xfff;
        Char encode3d[] = { b3 | 7, c | 0x3f, c | 0x3f };
                                                        int val3d = 0x7fff;
        Char encode3e[] = { b3 | 0xf, c | 0x3f, c | 0x3f };
                                                        int val3e = 0xffff;

        Char encode4a[] = { b4, c | 0x10, c, c };       int val4a = 0x10000;
        Char encode4b[] = { b4, c | 0x10, c, c | 0xf }; int val4b = 0x1000f;
        Char encode4c[] = { b4, c | 0x10, c | 0xf, c }; int val4c = 0x103c0;
        Char encode4d[] = { b4, c | 0x10, c | 0x30, c };int val4d = 0x10c00;
        Char encode4e[] = { b4, c | 0x13, c, c };       int val4e = 0x13000;
        Char encode4f[] = { b4, c | 0x1c, c, c };       int val4f = 0x1c000;
        Char encode4g[] = { b4 | 1, c, c, c };          int val4g = 0x40000;
        Char encode4h[] = { b4 | 3, c, c, c };          int val4h = 0xc0000;
        Char encode4i[] = { b4 | 4, c, c, c };          int val4i = 0x100000;
        Char encode4j[] = { b4 | 4, c | 0xf, c | 0x3f, c | 0x3f };
                                                        int val4j = 0x10ffff;

#define TEST(testId) do {                                                   \
            bsl::string str;                                                \
            str.insert(0, encode ## testId, sizeof(encode ## testId));      \
            Char *pc = str.data();                                          \
            const unsigned int val = decode(&pc);                           \
            ASSERT(pc == str.data() + str.length() + 0 * val ## testId);    \
            ASSERT(int(val) == val ## testId);                              \
            ASSERT(str == utf8Encode(val ## testId));                       \
            ASSERT(allValid(str));                                          \
        } while(false);

        TEST(1a);       TEST(1b);       TEST(1c);       TEST(1d);     TEST(1e);
        TEST(2a);       TEST(2b);       TEST(2c);       TEST(2d);     TEST(2e);
        TEST(3a);       TEST(3b);       TEST(3c);       TEST(3d);     TEST(3e);
        TEST(4a);       TEST(4b);       TEST(4c);       TEST(4d);     TEST(4e);
        TEST(4f);       TEST(4g);       TEST(4h);       TEST(4i);     TEST(4j);
#undef TEST

#define TEST(testId) do {                                                   \
            bsl::string str;                                                \
            str.insert(0, encode ## testId, sizeof(encode ## testId));      \
            Char *pc = str.data();                                          \
            const unsigned int val = decode(&pc);                           \
            ASSERT(pc == str.data() + str.length() + 0 * val ## testId);    \
            ASSERT(int(val) == val ## testId);                              \
            ASSERT(str == utf8Encode(val ## testId));                       \
            ASSERT(allValid(str));                                          \
            ASSERTV(val ## testId, 1 == allNumCodePoints(str));             \
            ASSERT(bsl::strlen(str.c_str()) == str.length());               \
        } while(false);

                        TEST(1b);       TEST(1c);       TEST(1d);     TEST(1e);
        TEST(2a);       TEST(2b);       TEST(2c);       TEST(2d);     TEST(2e);
        TEST(3a);       TEST(3b);       TEST(3c);       TEST(3d);     TEST(3e);
        TEST(4a);       TEST(4b);       TEST(4c);       TEST(4d);     TEST(4e);
        TEST(4f);       TEST(4g);       TEST(4h);       TEST(4i);     TEST(4j);
#undef TEST

        bsl::string s1 = STR(1a)+STR(2a)+STR(3a)+STR(4a)+STR(4f);
        Char *ps = s1.data();
        ASSERT(val1a == int(decode(&ps)));
        ASSERT(val2a == int(decode(&ps)));
        ASSERT(val3a == int(decode(&ps)));
        ASSERT(val4a == int(decode(&ps)));
        ASSERT(val4f == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));

        s1 = STR(2a)+STR(3a)+STR(4a)+STR(4f);
        ps = s1.data();
        ASSERT(val2a == int(decode(&ps)));
        ASSERT(val3a == int(decode(&ps)));
        ASSERT(val4a == int(decode(&ps)));
        ASSERT(val4f == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));
        ASSERT(bsl::strlen(s1.c_str()) == s1.length());

        s1 = STR(1b)+STR(2b)+STR(3b)+STR(4b)+STR(4g);
        ps = s1.data();
        ASSERT(val1b == int(decode(&ps)));
        ASSERT(val2b == int(decode(&ps)));
        ASSERT(val3b == int(decode(&ps)));
        ASSERT(val4b == int(decode(&ps)));
        ASSERT(val4g == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));
        ASSERT(bsl::strlen(s1.c_str()) == s1.length());

        s1 = STR(1c)+STR(2c)+STR(3c)+STR(4c)+STR(4h);
        ps = s1.data();
        ASSERT(val1c == int(decode(&ps)));
        ASSERT(val2c == int(decode(&ps)));
        ASSERT(val3c == int(decode(&ps)));
        ASSERT(val4c == int(decode(&ps)));
        ASSERT(val4h == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));
        ASSERT(bsl::strlen(s1.c_str()) == s1.length());

        s1 = STR(1d)+STR(2d)+STR(3d)+STR(4d)+STR(4i);
        ps = s1.data();
        ASSERT(val1d == int(decode(&ps)));
        ASSERT(val2d == int(decode(&ps)));
        ASSERT(val3d == int(decode(&ps)));
        ASSERT(val4d == int(decode(&ps)));
        ASSERT(val4i == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));
        ASSERT(bsl::strlen(s1.c_str()) == s1.length());

        s1 = STR(1e)+STR(2e)+STR(3e)+STR(4e)+STR(4j);
        ps = s1.data();
        ASSERT(val1e == int(decode(&ps)));
        ASSERT(val2e == int(decode(&ps)));
        ASSERT(val3e == int(decode(&ps)));
        ASSERT(val4e == int(decode(&ps)));
        ASSERT(val4j == int(decode(&ps)));
        ASSERT(ps == s1.data() + s1.length());
        ASSERT(allValid(s1));
        ASSERT(bsl::strlen(s1.c_str()) == s1.length());

        // random overlong values
        Char encode2o1[] = { b2 | 1, c | 0x3f };        int val2o1 = 0x7f;
        Char encode2o2[] = { b2 | 0, c | 3 };           int val2o2 = 0x3;
        Char encode3o1[] = { b3, c | 0x1f, c | 0x3f };  int val3o1 = 0x7ff;
        Char encode3o2[] = { b3, c | 0, c | 3 };        int val3o2 = 0x3;
        Char encode4o1[] = { b4, c | 0xf, c | 0x3f, c | 0x3f };
                                                        int val4o1 = 0xffff;
        Char encode4o2[] = { b4, c , c, c | 3 };        int val4o2 = 0x3;

#define TEST(testId) do {                                                   \
            bsl::string str = STR(testId);                                  \
            Char *pc = str.data();                                          \
            ASSERT(val ## testId == int(decode(&pc)));                      \
            ASSERT(pc == str.data() + str.length());                        \
            ASSERT(false == allValid(str));                                 \
        } while(false)

        TEST(2o1);          TEST(2o2);
        TEST(3o1);          TEST(3o2);
        TEST(4o1);          TEST(4o2);
#undef TEST

        // blatantly invalid strings
        Char encode1i1[] = { c };
        Char encode1i2[] = { c | 0x3f };

        Char encode2i1[] = { b2 | 2, 0 };
        Char encode2i2[] = { b2 | 2, b2 };
        Char encode2i3[] = { b2 | 2, b3 };
        Char encode2i4[] = { b2 | 2, b4 };
        Char encode2i5[] = { b2 | 2, b5 };
        Char encode2i6[] = { b2 | 2, b6 };
        Char encode2i7[] = { b2 | 2, b7 };
        Char encode2i8[] = { b2 | 2, char(0xff) };

        Char encode3i1[] = { b3, c | 0x20, 0 };
        Char encode3i2[] = { b3, c | 0x20, b2 };
        Char encode3i3[] = { b3, c | 0x20, b3 };
        Char encode3i4[] = { b3, c | 0x20, b4 };
        Char encode3i5[] = { b3, c | 0x20, b5 };
        Char encode3i6[] = { b3, c | 0x20, b6 };
        Char encode3i7[] = { b3, c | 0x20, b7 };
        Char encode3i8[] = { b3, c | 0x20, char(0xff) };
        Char encode3i9[] = { b3, 0x3f, c };
        Char encode3ia[] = { b3, b2, c };
        Char encode3ib[] = { b3, b3, c };
        Char encode3ic[] = { b3, b4, c };
        Char encode3id[] = { b3, b5, c };
        Char encode3ie[] = { b3, b6, c };
        Char encode3if[] = { b3, b7, c };
        Char encode3ig[] = { b3, char(0xff), c };

        Char encode4i1[] = { b4, c | 0x10, c, 0 };
        Char encode4i2[] = { b4, c | 0x10, c, b2 };
        Char encode4i3[] = { b4, c | 0x10, c, b3 };
        Char encode4i4[] = { b4, c | 0x10, c, b4 };
        Char encode4i5[] = { b4, c | 0x10, c, b5 };
        Char encode4i6[] = { b4, c | 0x10, c, b6 };
        Char encode4i7[] = { b4, c | 0x10, c, b7 };
        Char encode4i8[] = { b4, c | 0x10, c, char(0xff) };
        Char encode4i9[] = { b4, c | 0x10, 0, c };
        Char encode4ia[] = { b4, c | 0x10, b2, c };
        Char encode4ib[] = { b4, c | 0x10, b3, c };
        Char encode4ic[] = { b4, c | 0x10, b4, c };
        Char encode4id[] = { b4, c | 0x10, b5, c };
        Char encode4ie[] = { b4, c | 0x10, b6, c };
        Char encode4if[] = { b4, c | 0x10, b7, c };
        Char encode4ig[] = { b4, c | 0x10, char(0xff), c };
        Char encode4ih[] = { b4, 0, c, c };
        Char encode4ii[] = { b4, b2, c, c };
        Char encode4ij[] = { b4, b3, c, c };
        Char encode4ik[] = { b4, b4, c, c };
        Char encode4il[] = { b4, b5, c, c };
        Char encode4im[] = { b4, b6, c, c };
        Char encode4in[] = { b4, b7, c, c };
        Char encode4io[] = { b4, char(0xff), c, c };

        Char encode5i1[] = { b5, c, c, c, c };

        Char encode6i1[] = { b6, c, c, c, c, c };

        Char encode7i1[] = { b7, c, c, c, c, c, c };

        Char encode8i1[] = { char(0xff), c, c, c, c, c, c, c };

#define TEST(testId) do {                                                   \
            bsl::string str = STR(testId);                                  \
            ASSERT(! allValid(str));                                        \
        } while(false)

        TEST(1i1);      TEST(1i2);

        TEST(2i1);      TEST(2i2);      TEST(2i3);      TEST(2i4);
        TEST(2i5);      TEST(2i6);      TEST(2i7);      TEST(2i8);

        TEST(3i1);      TEST(3i2);      TEST(3i3);      TEST(3i4);
        TEST(3i5);      TEST(3i6);      TEST(3i7);      TEST(3i8);
        TEST(3i9);      TEST(3ia);      TEST(3ib);      TEST(3ic);
        TEST(3id);      TEST(3ie);      TEST(3if);      TEST(3ig);

        TEST(4i1);      TEST(4i2);      TEST(4i3);      TEST(4i4);
        TEST(4i5);      TEST(4i6);      TEST(4i7);      TEST(4i8);
        TEST(4i9);      TEST(4ia);      TEST(4ib);      TEST(4ic);
        TEST(4id);      TEST(4ie);      TEST(4if);      TEST(4ig);
        TEST(4ih);      TEST(4ii);      TEST(4ij);      TEST(4ik);
        TEST(4il);      TEST(4im);      TEST(4in);      TEST(4io);

        TEST(5i1);

        TEST(6i1);

        TEST(7i1);

        TEST(8i1);
#undef TEST

        // short strings, strings that are valid until the end too abruptly

        Char encode2s1[] = { b2 };

        Char encode3s1[] = { b3, c | 0x20 };
        Char encode3s2[] = { b3 };

        Char encode4s1[] = { b4, c | 0x10, c };
        Char encode4s2[] = { b4, c | 0x10 };
        Char encode4s3[] = { b4 };

#define TEST(testId) do {                                                   \
            bsl::string str = STR(testId);                                  \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(4a) + STR(testId) + STR(4a);                          \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(4a) + STR(testId);                                    \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(3a) + STR(testId) + STR(3a);                          \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(3a) + STR(testId);                                    \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(2a) + STR(testId) + STR(2a);                          \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(2a) + STR(testId);                                    \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(1b) + STR(testId) + STR(1b);                          \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(1b) + STR(testId);                                    \
            ASSERT(! allValid(str));                                        \
        } while(false)

        TEST(2s1);
        TEST(3s1);      TEST(3s2);
        TEST(4s1);      TEST(4s2);      TEST(4s3);
#undef TEST

        // surrogate values
        Char encode3u1[] = { b3 | 0xd, c | 0x20, c };        // 0xd800
        Char encode3u2[] = { b3 | 0xd, c | 0x20, c | 0x37 }; // 0xd837
        Char encode3u3[] = { b3 | 0xd, c | 0x30, c };        // 0xdc00
        Char encode3u4[] = { b3 | 0xd, c | 0x33, c | 0x3f }; // 0xdcff

#define TEST(testId) do {                                                   \
            bsl::string str = STR(testId);                                  \
            ASSERT(false == allValid(str));                                 \
                                                                            \
            str = STR(1b) + STR(testId) + STR(1b);                          \
                                                                            \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(2b) + STR(testId) + STR(2b);                          \
                                                                            \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(3b) + STR(testId) + STR(3b);                          \
                                                                            \
            ASSERT(! allValid(str));                                        \
                                                                            \
            str = STR(4b) + STR(testId) + STR(4b);                          \
                                                                            \
            ASSERT(! allValid(str));                                        \
        } while (false)

        TEST(3u1);
        TEST(3u2);
        TEST(3u3);
        TEST(3u4);
#undef TEST
      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST
        //
        // Concerns:
        //: 1 Test basic methods
        //
        // Plan:
        //: 1 Test the various test functions and verify that they work as
        //:   designed.
        //
        // Testing:
        //   BREATHING TEST
        // --------------------------------------------------------------------

        if (verbose) cout << "\n" "BREATHING TEST" "\n"
                                  "==============" "\n";

        randAccum = 0;
        bsl::string str;
        str.reserve(41);
        for (int i = 0; i < 40; i += 4) {
            bsl::string newcp = code32(randVal32());
            ASSERT(4 == Obj::numBytesInCodePoint(newcp.c_str()));
            ASSERT(4 == Obj::numBytesRaw(newcp, 1));
            str += newcp;
        }

        ASSERT(40 == str.length());
        ASSERT(10 == allNumCodePoints(str));
        ASSERT(40 == Obj::numBytesRaw(str, 10));
        ASSERT( 4 == Obj::numBytesInCodePoint(str.c_str()));

        bsl::string s2 = " ";
        ASSERT( 0 == Obj::appendUtf8CodePoint(&s2, decode(U8_10000)));
        ASSERT( 5 == s2.length());

        ASSERT(allValid(str));

        for (int i = 0; i <= 40; i += 4) {
            if (veryVeryVeryVerbose) Q(.);

            ASSERT(Obj::isValid(str.data(), i));
            bsl::string c = clone(str.data(), i);
            ASSERT(Obj::isValid(c.c_str()));

            ASSERT(i / 4 == Obj::numCharacters(str.data(), i));
            ASSERT(i / 4 == Obj::numCharacters(c.c_str()));

            ASSERT(i / 4 == Obj::numCodePointsRaw(str.data(), i));
            ASSERT(i / 4 == Obj::numCodePointsRaw(c.c_str()));

            if (40 == i) break;

            for (int j = i + 1; j < i + 4; ++ j) {
                if (veryVeryVeryVerbose) Q(.);

                ASSERT(false == Obj::isValid(str.data(), j));
                ASSERT(false == Obj::isValid(clone(str.data(), j).c_str()));
            }
        }

        {
            bsl::string overStr = str + code32(0xffff);

            ASSERT(44 == overStr.length());
            ASSERT(11 == allNumCodePoints(overStr));
            ASSERT(44 == Obj::numBytesRaw(overStr, 11));

            ASSERT(! allValid(overStr));

            for (int i = 0; i <= 40; i += 4) {
                if (veryVeryVeryVerbose) Q(.);

                ASSERT(Obj::isValid(str.data(), i));
                bsl::string c = clone(str.data(), i);
                ASSERT(Obj::isValid(c.c_str()));

                ASSERT(i / 4 == Obj::numCharacters(str.data(), i));
                ASSERT(i / 4 == Obj::numCharacters(c.c_str()));

                ASSERT(i / 4 == Obj::numCodePointsRaw(str.data(), i));
                ASSERT(i / 4 == Obj::numCodePointsRaw(c.c_str()));

                if (40 == i) break;

                for (int j = i + 1; j < i + 4; ++ j) {
                    if (veryVeryVeryVerbose) Q(.);

                    ASSERT(false == Obj::isValid(str.data(), j));
                    ASSERT(false == Obj::isValid(clone(str.data(),j).c_str()));
                }
            }
        }

        str = "";
        str.reserve(34);
        for (int i = 0; i < 30; i += 3) {
            if (veryVeryVeryVerbose) Q(.);

            bsl::string newcp = code24(randVal24(true));

            ASSERT(3 == Obj::numBytesInCodePoint(newcp.c_str()));
            ASSERT(3 == Obj::numBytesRaw(newcp, 1));

            str += newcp;
        }

        ASSERT(30 == str.length());
        ASSERT(10 == allNumCodePoints(str));
        ASSERT(30 == Obj::numBytesRaw(str, 10));
        ASSERT( 3 == Obj::numBytesInCodePoint(str.c_str()));

        ASSERT(allValid(str));

        for (int i = 0; i <= 30; i += 3) {
            if (veryVeryVeryVerbose) Q(.);

            ASSERT(Obj::isValid(str.data(), i));
            bsl::string c = clone(str.data(), i);
            ASSERT(Obj::isValid(c.c_str()));

            ASSERT(i / 3 == Obj::numCharacters(str.data(), i));
            ASSERT(i / 3 == Obj::numCharacters(c.c_str()));

            ASSERT(i / 3 == Obj::numCodePointsRaw(str.data(), i));
            ASSERT(i / 3 == Obj::numCodePointsRaw(c.c_str()));

            if (30 == i) break;

            for (int j = i + 1; j < i + 3; ++ j) {
                if (veryVeryVeryVerbose) Q(.);

                ASSERT(false == Obj::isValid(str.data(), j));
                ASSERT(false == Obj::isValid(clone(str.data(), j).c_str()));
            }
        }

        {
            bsl::string surStr = str + code24(0xdddd);    // surrogate value

            ASSERT(33 == surStr.length());
            ASSERT(11 == allNumCodePoints(surStr));

            ASSERT(! Obj::isValid(surStr.data(), surStr.length()));
            ASSERT(! Obj::isValid(surStr.c_str()));

            for (int i = 0; i <= 33; i += 3) {
                if (veryVeryVeryVerbose) Q(.);

                bool tst = i < 33;
                ASSERT(tst == Obj::isValid(surStr.data(), i));
                bsl::string c = clone(surStr.data(), i);
                ASSERT(tst == Obj::isValid(c.c_str()));

                ASSERT(i / 3 == Obj::numCharacters(surStr.data(), i));
                ASSERT(i / 3 == Obj::numCharacters(c.c_str()));

                ASSERT(i / 3 == Obj::numCodePointsRaw(surStr.data(), i));
                ASSERT(i / 3 == Obj::numCodePointsRaw(c.c_str()));

                if (!tst) break;

                for (int j = i + 1; j < i + 3; ++ j) {
                    if (veryVeryVeryVerbose) Q(.);

                    ASSERT(! Obj::isValid(surStr.data(), j));
                    ASSERT(! Obj::isValid(clone(surStr.data(), j).c_str()));
                }
            }
        }

        {
            bsl::string overStr = str + code24(0x7ff);    // overlong value

            ASSERT(33 == overStr.length());
            ASSERT(11 == allNumCodePoints(overStr));

            ASSERT(! allValid(overStr));

            for (int i = 0; i <= 33; i += 3) {
                if (veryVeryVeryVerbose) Q(.);

                bool tst = i < 33;
                bsl::string c = clone(overStr.data(), i);
                ASSERT(tst == allValid(c));

                ASSERT(i / 3 == Obj::numCharacters(overStr.data(), i));
                ASSERT(i / 3 == Obj::numCharacters(
                                            clone(overStr.data(), i).c_str()));

                ASSERT(i / 3 == Obj::numCodePointsRaw(overStr.data(), i));
                ASSERT(i / 3 == Obj::numCodePointsRaw(
                                            clone(overStr.data(), i).c_str()));

                if (!tst) break;

                for (int j = i + 1; j < i + 3; ++ j) {
                    if (veryVeryVeryVerbose) Q(.);

                    ASSERT(! Obj::isValid(overStr.data(), j));
                    ASSERT(! Obj::isValid(clone(overStr.data(), j).c_str()));
                }
            }
        }

        str = "";
        str.reserve(23);
        for (int i = 0; i < 20; i += 2) {
            if (veryVeryVeryVerbose) Q(.);

            int val;
            do {
                val = randVal16();
            } while (0 == val);
            bsl::string newcp = code16(val);

            ASSERT(2 == Obj::numBytesInCodePoint(newcp.c_str()));
            ASSERT(2 == Obj::numBytesRaw(newcp, 1));

            str += newcp;
        }

        ASSERT(20 == str.length());
        ASSERT(10 == allNumCodePoints(str));
        ASSERT(20 == Obj::numBytesRaw(str, 10));
        ASSERT( 2 == Obj::numBytesInCodePoint(str.c_str()));

        ASSERT(allValid(str));

        for (int i = 0; i <= 20; i += 2) {
            if (veryVeryVeryVerbose) Q(.);

            ASSERT(Obj::isValid(str.data(), i));
            bsl::string c = clone(str.data(), i);
            ASSERT(Obj::isValid(c.c_str()));

            ASSERT(i / 2 == Obj::numCharacters(str.data(), i));
            ASSERT(i / 2 == Obj::numCharacters(c.c_str()));

            ASSERT(i / 2 == Obj::numCodePointsRaw(str.data(), i));
            ASSERT(i / 2 == Obj::numCodePointsRaw(c.c_str()));

            if (20 == i) break;

            for (int j = i + 1; j < i + 2; ++ j) {
                if (veryVeryVeryVerbose) Q(.);

                ASSERT(false == Obj::isValid(str.data(), j));
                ASSERT(false == Obj::isValid(clone(str.data(), j).c_str()));
            }
        }

        {
            bsl::string overStr = str + code16(0);       // overlong zero value

            ASSERT(22 == overStr.length());
            ASSERT(11 == allNumCodePoints(overStr));

            ASSERT(false == allValid(overStr));

            for (int i = 0; i <= 22; i += 2) {
                if (veryVeryVeryVerbose) Q(.);

                bool tst = i < 22;
                ASSERT(tst == Obj::isValid(overStr.data(), i));
                bsl::string c = clone(overStr.data(), i);
                ASSERT(tst == Obj::isValid(c.c_str()));

                ASSERT(i / 2 == Obj::numCharacters(overStr.data(), i));
                ASSERT(i / 2 == Obj::numCharacters(c.c_str()));

                ASSERT(i / 2 == Obj::numCodePointsRaw(overStr.data(), i));
                ASSERT(i / 2 == Obj::numCodePointsRaw(c.c_str()));

                if (!tst) break;

                for (int j = i + 1; j < i + 2; ++ j) {
                    if (veryVeryVeryVerbose) Q(.);

                    ASSERT(false == Obj::isValid(overStr.data(), j));
                    ASSERT(false == Obj::isValid(
                                            clone(overStr.data(), j).c_str()));
                }
            }
        }

        {
            bsl::string overStr = str + code16(0x7f);// overlong non-zero value

            ASSERT(22 == overStr.length());
            ASSERT(11 == allNumCodePoints(overStr));

            ASSERT(false == allValid(overStr));

            for (int i = 0; i <= 22; i += 2) {
                if (veryVeryVeryVerbose) Q(.);

                bool tst = i < 22;
                ASSERT(tst == Obj::isValid(overStr.data(), i));
                bsl::string c = clone(overStr.data(), i);
                ASSERT(tst == Obj::isValid(c.c_str()));

                ASSERT(i / 2 == Obj::numCharacters(overStr.data(), i));
                ASSERT(i / 2 == Obj::numCharacters(c.c_str()));

                ASSERT(i / 2 == Obj::numCodePointsRaw(overStr.data(), i));
                ASSERT(i / 2 == Obj::numCodePointsRaw(c.c_str()));

                if (!tst) break;

                for (int j = i + 1; j < i + 2; ++ j) {
                    if (veryVeryVeryVerbose) Q(.);

                    ASSERT(false == Obj::isValid(overStr.data(), j));
                    ASSERT(false == Obj::isValid(
                                            clone(overStr.data(), j).c_str()));
                }
            }
        }

        str = "";
        str.reserve(14);
        for (int i = 0; i < 10; ++ i) {
            bsl::string newcp = code8(randVal8(true));
            ASSERT(1 == Obj::numBytesInCodePoint(newcp.c_str()));
            ASSERT(1 == Obj::numBytesRaw(newcp, 1));
            str += newcp;
        }

        ASSERT(10 == str.length());
        ASSERT(10 == allNumCodePoints(str));
        ASSERT(10 == Obj::numBytesRaw(str, 10));

        ASSERT(allValid(str));

        for (int i = 0; i <= 10; ++ i) {
            if (veryVeryVeryVerbose) Q(.);

            ASSERT(Obj::isValid(str.data(), i));
            bsl::string c = clone(str.data(), i);
            ASSERT(Obj::isValid(c.c_str()));

            ASSERT(i == Obj::numCharacters(str.data(), i));
            ASSERT(i == Obj::numCharacters(c.c_str()));

            ASSERT(i == Obj::numCodePointsRaw(str.data(), i));
            ASSERT(i == Obj::numCodePointsRaw(c.c_str()));
        }

        {
            bsl::string zStr = str + code8(0);
            zStr += code8(randVal8());
            zStr += code8(randVal8());
            zStr += code8(randVal8());

            ASSERT(14 == zStr.length());
            ASSERT(14 == Obj::numCharacters(zStr.data(), 14));
            ASSERT(10 == Obj::numCharacters(zStr.data()));

            ASSERT(14 == Obj::numCodePointsRaw(zStr.data(), 14));
            ASSERT(10 == Obj::numCodePointsRaw(zStr.data()));

            ASSERT(allValid(zStr));

            for (int i = 0; i <= 14; ++ i) {
                if (veryVeryVeryVerbose) Q(.);

                ASSERT(Obj::isValid(zStr.data(), i));
                bsl::string c = clone(zStr.data(), i);
                ASSERT(Obj::isValid(c.c_str()));

                ASSERT(i == Obj::numCharacters(zStr.data(), i));
                ASSERT((i <= 10 ? i : 10) == Obj::numCharacters(c.c_str()));

                ASSERT(i == Obj::numCodePointsRaw(zStr.data(), i));
                ASSERT((i <= 10 ? i : 10) == Obj::numCodePointsRaw(c.c_str()));
            }
        }
      } break;
      case -1: {
        // --------------------------------------------------------------------
        // RANDOM NUMBER GENERATORS TEST
        //
        // Concerns:
        //: 1 Random number generators work properly.
        //
        // Plan:
        //: 1 Test the various random number generators 2 ways -- print out a
        //:   bunch of values for visual inspection, and run a much larger
        //:   number of values for programmatic verification.
        //
        // Testing:
        //   random number generator
        // --------------------------------------------------------------------

        if (verbose) cout << "RANDOM NUMBER GENERATORS TEST\n"
                             "=============================\n";

        cout << "randVal8()\n";
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 16; ++j) {
                cout << (j ? ", " : "") << randVal8();
            }
            cout << endl;
        }

        randAccum = 0;
        cout << "\nrandVal8(true)\n";
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 16; ++j) {
                cout << (j ? ", " : "") << randVal8(true);
            }
            cout << endl;
        }
        for (int i = 10 * 1000; i > 0; --i) {
            int j = randVal8(true);
            ASSERT((0 != j) & (0 == (~0x7f & j)));
        }

        randAccum = 0;
        cout << "\nrandVal16()\n";
        for (int i = 0; i < 60; ++i) {
            for (int j = 0; j < 10; ++j) {
                cout << (j ? ", " : "") << "0x" << bsl::hex << randVal16();
            }
            cout << endl;
        }
        for (int i = 100 * 1000; i > 0; --i) {
            int j = randVal16();
            ASSERT((j >= 0x80) & (j <= 0x7ff));
        }

        randAccum = 0;
        cout << "\nrandVal24(false)\n";
        for (int i = 0; i < 60; ++i) {
            for (int j = 0; j < 10; ++j) {
                cout << (j ? ", " : "") << "0x" << bsl::hex << randVal24();
            }
            cout << endl;
        }
        for (int i = 100 * 1000; i > 0; --i) {
            int j = randVal24();
            ASSERT((j >= 0x800) & (j <= 0xffff));
        }

        randAccum = 0;
        cout << "\nrandVal24(true)\n";
        for (int i = 0; i < 60; ++i) {
            for (int j = 0; j < 10; ++j) {
                cout << (j ? ", " : "") << "0x" << bsl::hex << randVal24(true);
            }
            cout << endl;
        }
        for (int i = 100 * 1000; i > 0; --i) {
            int j = randVal24(true);
            ASSERT((j >= 0x800) & (j <= 0xffff) &
                                             !((j >= 0xd800) & (j <= 0xdfff)));
        }

        randAccum = 0;
        cout << "\nrandVal32()\n";
        for (int i = 0; i < 60; ++i) {
            for (int j = 0; j < 8; ++j) {
                cout << (j ? ", " : "") << "0x" << bsl::hex << randVal32();
            }
            cout << endl;
        }
        int highest = 0;
        for (int i = 1000 * 1000; i > 0; --i) {
            int j = randVal32();
            ASSERT((j >= 0x10000) & (j <= 0x10ffff));
            if (j > highest) highest = j;
        }
        cout << "highest randVal32: " << highest << endl;
      } break;
      case -2: {
        // --------------------------------------------------------------------
        // VERIFY TEST APPARATUS
        //
        // Concerns:
        //: 1 The test apparatus works properly.
        //
        // Plan:
        //: 1 Test the various test functions and verify that they work as
        //:   expected.
        //
        // Testing:
        //   'utf8Encode', 'decode'
        // --------------------------------------------------------------------

        if (verbose) cout << "\nVERIFY TEST APPARATUS\n"
                               "=====================\n";

        cout << "Encode / Decode cycle\n";

        randAccum = 0;
        bsl::string str;

        {
            randAccum = 0;
            cout << "Encode:\n";
            str.reserve(7 * 7 * 4 + 1);
            int valStore[7][7];
            for (int row = 0; row < 7; ++ row) {
                for (int col = 0; col < 7; ++ col) {
                    int val = randValue(true);
                    cout << (col ? ", " : "") << "0x" << bsl::hex << val;
                    str += utf8Encode(val);
                    valStore[row][col] = val;
                }
                cout << endl;
            }

            ASSERT(str.length() < 7 * 7 * 4 + 1);

            cout << "Decode:\n";
            const char *pc = str.data();
            for (int row = 0; row < 7; ++ row) {
                for (int col = 0; col < 7; ++ col) {
                    int val = decode(&pc);
                    cout << (col ? ", " : "") << "0x" << bsl::hex << val;
                    ASSERT(valStore[row][col] == val);
                }
                cout << endl;
            }
            ASSERT(pc == str.data() + str.length());
        }

        {
            randAccum = 0;
            str = "";
            str.reserve(100 * 100 * 4 + 1);
            int valStore[100][100];
            for (int row = 0; row < 100; ++ row) {
                for (int col = 0; col < 100; ++ col) {
                    int val = randValue(true);
                    str += utf8Encode(val);
                    valStore[row][col] = val;
                }
            }

            ASSERT(str.length() < 100 * 100 * 4 + 1);

            const char *pc = str.data();
            for (int row = 0; row < 100; ++ row) {
                for (int col = 0; col < 100; ++ col) {
                    int val = decode(&pc);
                    ASSERT(valStore[row][col] == val);
                }
            }
            ASSERT(pc == str.data() + str.length());
            ASSERT(bsl::strlen(str.c_str()) < str.length());
        }

        {
            randAccum = 0;
            str = "";
            str.reserve(100 * 100 * 4 + 1);
            int valStore[100][100];
            for (int row = 0; row < 100; ++ row) {
                for (int col = 0; col < 100; ++ col) {
                    int val = randValue(true, true);
                    str += utf8Encode(val);
                    valStore[row][col] = val;
                }
            }

            ASSERT(str.length() < 100 * 100 * 4 + 1);

            const char *pc = str.data();
            for (int row = 0; row < 100; ++ row) {
                for (int col = 0; col < 100; ++ col) {
                    int val = decode(&pc);
                    ASSERT(valStore[row][col] == val);
                }
            }
            ASSERT(pc == str.data() + str.length());
            ASSERT(bsl::strlen(str.c_str()) == str.length());
        }
      } break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }
    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "." << endl;
    }
    return testStatus;
}

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
